aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMelanie2013-04-28 19:03:39 +0200
committerMelanie2013-04-28 19:03:39 +0200
commit4275d7a839d7380ee50aeadc38a31dd467bd891e (patch)
tree1e589fc3b448b580d1cc25b52215ef5ce2d7ae78 /OpenSim
parentMerge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork (diff)
parentController module for dynamic floaters (WIP) (diff)
downloadopensim-SC_OLD-4275d7a839d7380ee50aeadc38a31dd467bd891e.zip
opensim-SC_OLD-4275d7a839d7380ee50aeadc38a31dd467bd891e.tar.gz
opensim-SC_OLD-4275d7a839d7380ee50aeadc38a31dd467bd891e.tar.bz2
opensim-SC_OLD-4275d7a839d7380ee50aeadc38a31dd467bd891e.tar.xz
Merge branch 'avination-current' of ssh://3dhosting.de/var/git/careminster into avination-current
Conflicts: bin/Regions/Regions.ini.example
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Addons/Groups/ForeignImporter.cs77
-rw-r--r--OpenSim/Addons/Groups/GroupsExtendedData.cs509
-rw-r--r--OpenSim/Addons/Groups/GroupsMessagingModule.cs594
-rw-r--r--OpenSim/Addons/Groups/GroupsModule.cs1467
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs289
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs717
-rw-r--r--OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs444
-rw-r--r--OpenSim/Addons/Groups/IGroupsServicesConnector.cs118
-rw-r--r--OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs347
-rw-r--r--OpenSim/Addons/Groups/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs642
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs434
-rw-r--r--OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs760
-rw-r--r--OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs831
-rw-r--r--OpenSim/Addons/Groups/Service/GroupsService.cs1020
-rw-r--r--OpenSim/Addons/Groups/Service/GroupsServiceBase.cs84
-rw-r--r--OpenSim/Addons/Groups/Service/HGGroupsService.cs353
-rw-r--r--OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs267
-rw-r--r--OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs143
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs215
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs131
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs83
-rw-r--r--OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs5
-rw-r--r--OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs24
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs67
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs1465
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml11
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs551
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs860
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs383
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs448
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs662
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs2343
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs246
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs46
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs204
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs228
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs136
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs122
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs98
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml11
-rw-r--r--OpenSim/ApplicationPlugins/Rest/RestPlugin.cs417
-rw-r--r--OpenSim/ApplicationPlugins/Rest/rest.xsd276
-rw-r--r--OpenSim/Capabilities/Caps.cs13
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs35
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs2
-rw-r--r--OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs2
-rw-r--r--OpenSim/Capabilities/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/ConsoleClient/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/ConsoleClient/Requester.cs19
-rw-r--r--OpenSim/Data/IGroupsData.cs144
-rw-r--r--OpenSim/Data/IOfflineIMData.cs (renamed from OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs)27
-rw-r--r--OpenSim/Data/IPresenceData.cs1
-rw-r--r--OpenSim/Data/IXGroupData.cs (renamed from OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs)60
-rw-r--r--OpenSim/Data/MSSQL/MSSQLAssetData.cs8
-rw-r--r--OpenSim/Data/MSSQL/MSSQLPresenceData.cs13
-rw-r--r--OpenSim/Data/MSSQL/MSSQLSimulationData.cs33
-rw-r--r--OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Data/MSSQL/Resources/RegionStore.migrations20
-rw-r--r--OpenSim/Data/MySQL/MySQLAssetData.cs8
-rw-r--r--OpenSim/Data/MySQL/MySQLGenericTableHandler.cs60
-rw-r--r--OpenSim/Data/MySQL/MySQLGroupsData.cs484
-rw-r--r--OpenSim/Data/MySQL/MySQLOfflineIMData.cs (renamed from OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs)54
-rw-r--r--OpenSim/Data/MySQL/MySQLPresenceData.cs14
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs31
-rw-r--r--OpenSim/Data/MySQL/MySQLXAssetData.cs177
-rw-r--r--OpenSim/Data/MySQL/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Data/MySQL/Resources/IM_Store.migrations24
-rw-r--r--OpenSim/Data/MySQL/Resources/RegionStore.migrations20
-rw-r--r--OpenSim/Data/MySQL/Resources/XAssetStore.migrations30
-rw-r--r--OpenSim/Data/MySQL/Resources/os_groups_Store.migrations115
-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.cs (renamed from OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs)73
-rw-r--r--OpenSim/Data/Null/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Data/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Data/SQLite/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Data/SQLite/Resources/RegionStore.migrations17
-rw-r--r--OpenSim/Data/SQLite/SQLiteAssetData.cs28
-rw-r--r--OpenSim/Data/SQLite/SQLiteSimulationData.cs37
-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/AssemblyInfo.cs3
-rw-r--r--OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/AvatarAppearance.cs83
-rw-r--r--OpenSim/Framework/Communications/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs32
-rw-r--r--OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Console/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Console/CommandConsole.cs10
-rw-r--r--OpenSim/Framework/Console/ConsoleDisplayTable.cs15
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs36
-rw-r--r--OpenSim/Framework/DAMap.cs273
-rw-r--r--OpenSim/Framework/DOMap.cs (renamed from OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs)90
-rw-r--r--OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs508
-rw-r--r--OpenSim/Framework/IClientAPI.cs6
-rw-r--r--OpenSim/Framework/ILandChannel.cs7
-rw-r--r--OpenSim/Framework/Monitoring/AssetStatsCollector.cs26
-rw-r--r--OpenSim/Framework/Monitoring/BaseStatsCollector.cs7
-rw-r--r--OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs9
-rw-r--r--OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs29
-rwxr-xr-xOpenSim/Framework/Monitoring/Stats/CounterStat.cs228
-rw-r--r--OpenSim/Framework/Monitoring/Stats/Stat.cs26
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs69
-rw-r--r--OpenSim/Framework/Monitoring/UserStatsCollector.cs18
-rw-r--r--OpenSim/Framework/PluginManager.cs563
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs32
-rw-r--r--OpenSim/Framework/RegionInfo.cs27
-rw-r--r--OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs5
-rw-r--r--OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs4
-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.cs124
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs253
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs14
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs (renamed from OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs)12
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs150
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs18
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestSessionService.cs15
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs1102
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs11
-rw-r--r--OpenSim/Framework/Servers/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs131
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs8
-rw-r--r--OpenSim/Framework/Servers/Tests/VersionInfoTests.cs3
-rw-r--r--OpenSim/Framework/Servers/VersionInfo.cs2
-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.cs278
-rw-r--r--OpenSim/Framework/WebUtil.cs61
-rw-r--r--OpenSim/Region/Application/Application.cs45
-rw-r--r--OpenSim/Region/Application/OpenSim.cs67
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs37
-rw-r--r--OpenSim/Region/ClientStack/ClientStackManager.cs83
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs29
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs34
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs33
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs81
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs88
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs159
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs4
-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/ClientStack/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs21
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs177
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs687
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs283
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs289
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs13
-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/InventoryArchiveReadRequest.cs22
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs86
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs18
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs)149
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs194
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs)265
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs138
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs41
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs119
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs139
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs542
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs141
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs38
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs12
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs7
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs10
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs46
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs15
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs79
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs87
-rw-r--r--OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs14
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs8
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs9
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs67
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs20
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs317
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs129
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandChannel.cs5
-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/LegacyMap/MapImageModule.cs110
-rw-r--r--OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs73
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs55
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs39
-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/Warp3DMap/Warp3DImageModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/World/Wind/WindModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs11
-rw-r--r--OpenSim/Region/DataSnapshot/DataSnapshotManager.cs48
-rw-r--r--OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs10
-rw-r--r--OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs51
-rw-r--r--OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs57
-rw-r--r--OpenSim/Region/Framework/Interfaces/IHttpRequests.cs3
-rw-r--r--OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs30
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs (renamed from OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs)28
-rw-r--r--OpenSim/Region/Framework/Interfaces/IScriptModule.cs11
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs6
-rw-r--r--OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs1
-rw-r--r--OpenSim/Region/Framework/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs15
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs57
-rw-r--r--OpenSim/Region/Framework/Scenes/Border.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/EntityManager.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs124
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs513
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs102
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs628
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs32
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs65
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs255
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs362
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs119
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs107
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs22
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs20
-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/ScenePresenceAgentTests.cs103
-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/ScenePresenceCrossingTests.cs162
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs137
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs10
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs200
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs18
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs158
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs283
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs96
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs21
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs12
-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.cs173
-rw-r--r--OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs175
-rw-r--r--OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs339
-rwxr-xr-xOpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs19
-rw-r--r--OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs4
-rwxr-xr-xOpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs171
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs391
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs155
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs307
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs901
-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/ViewerSupport/DynamicFloaterModule.cs228
-rw-r--r--OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs282
-rw-r--r--OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs31
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs4
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs4
-rw-r--r--OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs266
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs13
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs1987
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs2311
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs683
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs554
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs27
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs64
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1264
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs104
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs439
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs113
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs203
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs590
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs815
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs366
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1255
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs153
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs182
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs1047
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs558
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs183
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs314
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs287
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs1015
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs269
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt346
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs150
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs95
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs4
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/Physics/Manager/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs3
-rwxr-xr-xOpenSim/Region/Physics/Manager/IPhysicsParameters.cs6
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs15
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs15
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs9
-rw-r--r--OpenSim/Region/Physics/Meshing/Mesh.cs2
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs26
-rw-r--r--OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs2
-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.cs7
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs3
-rw-r--r--OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs2
-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/Mesh.cs2
-rw-r--r--OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs6
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs4
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs6
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs6
-rw-r--r--OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs5
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs8
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs43
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs73
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs834
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs79
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs150
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs80
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs52
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs30
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs10
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs147
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs84
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs4
-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/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs256
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs513
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs31
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs249
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs270
-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.cs18
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs23
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs61
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/EventManager.cs10
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs126
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs (renamed from OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs)2
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs271
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs6
-rw-r--r--OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs84
-rw-r--r--OpenSim/Region/UserStatistics/Clients_report.cs27
-rw-r--r--OpenSim/Region/UserStatistics/Default_Report.cs27
-rw-r--r--OpenSim/Region/UserStatistics/IStatsReport.cs1
-rw-r--r--OpenSim/Region/UserStatistics/LogLinesAJAX.cs29
-rw-r--r--OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Region/UserStatistics/Prototype_distributor.cs31
-rw-r--r--OpenSim/Region/UserStatistics/Sessions_Report.cs5
-rw-r--r--OpenSim/Region/UserStatistics/SimStatsAJAX.cs59
-rw-r--r--OpenSim/Region/UserStatistics/Updater_distributor.cs4
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs72
-rw-r--r--OpenSim/Server/Base/CommandManager.cs359
-rw-r--r--OpenSim/Server/Base/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs226
-rw-r--r--OpenSim/Server/Base/ServicesServerBase.cs11
-rw-r--r--OpenSim/Server/Handlers/Base/ServerConnector.cs67
-rw-r--r--OpenSim/Server/Handlers/Grid/GridInfoHandlers.cs21
-rw-r--r--OpenSim/Server/Handlers/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Server/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Server/ServerMain.cs12
-rw-r--r--OpenSim/Services/AssetService/AssetService.cs32
-rw-r--r--OpenSim/Services/AssetService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/AssetService/XAssetService.cs63
-rw-r--r--OpenSim/Services/AssetService/XAssetServiceBase.cs47
-rw-r--r--OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/Base/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs14
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs69
-rw-r--r--OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs34
-rw-r--r--OpenSim/Services/Connectors/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs47
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs3
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs2
-rw-r--r--OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs2
-rw-r--r--OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/Friends/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/GridService/GridService.cs14
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs7
-rw-r--r--OpenSim/Services/GridService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/HypergridService/GatekeeperService.cs4
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs35
-rw-r--r--OpenSim/Services/HypergridService/HGInventoryService.cs6
-rw-r--r--OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs4
-rw-r--r--OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs12
-rw-r--r--OpenSim/Services/Interfaces/IAvatarService.cs21
-rw-r--r--OpenSim/Services/Interfaces/IOfflineIMService.cs115
-rw-r--r--OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/InventoryService/LibraryService.cs1
-rw-r--r--OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/InventoryService/XInventoryService.cs11
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs18
-rw-r--r--OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Services/UserAccountService/UserAccountService.cs5
-rw-r--r--OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs91
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs39
-rw-r--r--OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs32
-rw-r--r--OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs109
-rw-r--r--OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs77
-rw-r--r--OpenSim/Tests/Common/Mock/MockScriptEngine.cs266
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs37
-rw-r--r--OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs178
-rw-r--r--OpenSim/Tests/Common/Mock/TestLandChannel.cs5
-rw-r--r--OpenSim/Tests/Common/Mock/TestScene.cs3
-rw-r--r--OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs25
-rw-r--r--OpenSim/Tests/Common/TestHelpers.cs21
-rw-r--r--OpenSim/Tests/ConfigurationLoaderTest.cs7
-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--OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Tools/Configger/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Tools/pCampBot/Bot.cs5
-rw-r--r--OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs4
523 files changed, 42022 insertions, 17552 deletions
diff --git a/OpenSim/Addons/Groups/ForeignImporter.cs b/OpenSim/Addons/Groups/ForeignImporter.cs
new file mode 100644
index 0000000..788d21d
--- /dev/null
+++ b/OpenSim/Addons/Groups/ForeignImporter.cs
@@ -0,0 +1,77 @@
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;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33
34namespace OpenSim.Groups
35{
36 public class ForeignImporter
37 {
38 IUserManagement m_UserManagement;
39 public ForeignImporter(IUserManagement uman)
40 {
41 m_UserManagement = uman;
42 }
43
44 public GroupMembersData ConvertGroupMembersData(ExtendedGroupMembersData _m)
45 {
46 GroupMembersData m = new GroupMembersData();
47 m.AcceptNotices = _m.AcceptNotices;
48 m.AgentPowers = _m.AgentPowers;
49 m.Contribution = _m.Contribution;
50 m.IsOwner = _m.IsOwner;
51 m.ListInProfile = _m.ListInProfile;
52 m.OnlineStatus = _m.OnlineStatus;
53 m.Title = _m.Title;
54
55 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
56 Util.ParseUniversalUserIdentifier(_m.AgentID, out m.AgentID, out url, out first, out last, out tmp);
57 if (url != string.Empty)
58 m_UserManagement.AddUser(m.AgentID, first, last, url);
59
60 return m;
61 }
62
63 public GroupRoleMembersData ConvertGroupRoleMembersData(ExtendedGroupRoleMembersData _rm)
64 {
65 GroupRoleMembersData rm = new GroupRoleMembersData();
66 rm.RoleID = _rm.RoleID;
67
68 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
69 Util.ParseUniversalUserIdentifier(_rm.MemberID, out rm.MemberID, out url, out first, out last, out tmp);
70 if (url != string.Empty)
71 m_UserManagement.AddUser(rm.MemberID, first, last, url);
72
73 return rm;
74 }
75
76 }
77}
diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs
new file mode 100644
index 0000000..6f4db28
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs
@@ -0,0 +1,509 @@
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;
30
31using OpenSim.Framework;
32using OpenMetaverse;
33
34namespace OpenSim.Groups
35{
36 public class ExtendedGroupRecord : GroupRecord
37 {
38 public int MemberCount;
39 public int RoleCount;
40 public string ServiceLocation;
41 public string FounderUUI;
42 }
43
44 public class ExtendedGroupMembershipData : GroupMembershipData
45 {
46 public string AccessToken;
47 }
48
49 public class ExtendedGroupMembersData
50 {
51 // This is the only difference: this is a string
52 public string AgentID;
53 public int Contribution;
54 public string OnlineStatus;
55 public ulong AgentPowers;
56 public string Title;
57 public bool IsOwner;
58 public bool ListInProfile;
59 public bool AcceptNotices;
60 public string AccessToken;
61 }
62
63 public class ExtendedGroupRoleMembersData
64 {
65 public UUID RoleID;
66 // This is the only difference: this is a string
67 public string MemberID;
68
69 }
70
71 public struct ExtendedGroupNoticeData
72 {
73 public UUID NoticeID;
74 public uint Timestamp;
75 public string FromName;
76 public string Subject;
77 public bool HasAttachment;
78 public byte AttachmentType;
79 public string AttachmentName;
80 public UUID AttachmentItemID;
81 public string AttachmentOwnerID;
82
83 public GroupNoticeData ToGroupNoticeData()
84 {
85 GroupNoticeData n = new GroupNoticeData();
86 n.FromName = this.FromName;
87 n.AssetType = this.AttachmentType;
88 n.HasAttachment = this.HasAttachment;
89 n.NoticeID = this.NoticeID;
90 n.Subject = this.Subject;
91 n.Timestamp = this.Timestamp;
92
93 return n;
94 }
95 }
96
97 public class GroupsDataUtils
98 {
99 public static string Sanitize(string s)
100 {
101 return s == null ? string.Empty : s;
102 }
103
104 public static Dictionary<string, object> GroupRecord(ExtendedGroupRecord grec)
105 {
106 Dictionary<string, object> dict = new Dictionary<string, object>();
107 if (grec == null)
108 return dict;
109
110 dict["AllowPublish"] = grec.AllowPublish.ToString();
111 dict["Charter"] = Sanitize(grec.Charter);
112 dict["FounderID"] = grec.FounderID.ToString();
113 dict["FounderUUI"] = Sanitize(grec.FounderUUI);
114 dict["GroupID"] = grec.GroupID.ToString();
115 dict["GroupName"] = Sanitize(grec.GroupName);
116 dict["InsigniaID"] = grec.GroupPicture.ToString();
117 dict["MaturePublish"] = grec.MaturePublish.ToString();
118 dict["MembershipFee"] = grec.MembershipFee.ToString();
119 dict["OpenEnrollment"] = grec.OpenEnrollment.ToString();
120 dict["OwnerRoleID"] = grec.OwnerRoleID.ToString();
121 dict["ServiceLocation"] = Sanitize(grec.ServiceLocation);
122 dict["ShownInList"] = grec.ShowInList.ToString();
123 dict["MemberCount"] = grec.MemberCount.ToString();
124 dict["RoleCount"] = grec.RoleCount.ToString();
125
126 return dict;
127 }
128
129 public static ExtendedGroupRecord GroupRecord(Dictionary<string, object> dict)
130 {
131 if (dict == null)
132 return null;
133
134 ExtendedGroupRecord grec = new ExtendedGroupRecord();
135 if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
136 grec.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
137
138 if (dict.ContainsKey("Charter") && dict["Charter"] != null)
139 grec.Charter = dict["Charter"].ToString();
140 else
141 grec.Charter = string.Empty;
142
143 if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
144 grec.FounderID = UUID.Parse(dict["FounderID"].ToString());
145
146 if (dict.ContainsKey("FounderUUI") && dict["FounderUUI"] != null)
147 grec.FounderUUI = dict["FounderUUI"].ToString();
148 else
149 grec.FounderUUI = string.Empty;
150
151 if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
152 grec.GroupID = UUID.Parse(dict["GroupID"].ToString());
153
154 if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
155 grec.GroupName = dict["GroupName"].ToString();
156 else
157 grec.GroupName = string.Empty;
158
159 if (dict.ContainsKey("InsigniaID") && dict["InsigniaID"] != null)
160 grec.GroupPicture = UUID.Parse(dict["InsigniaID"].ToString());
161
162 if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
163 grec.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
164
165 if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
166 grec.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
167
168 if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
169 grec.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
170
171 if (dict.ContainsKey("OwnerRoleID") && dict["OwnerRoleID"] != null)
172 grec.OwnerRoleID = UUID.Parse(dict["OwnerRoleID"].ToString());
173
174 if (dict.ContainsKey("ServiceLocation") && dict["ServiceLocation"] != null)
175 grec.ServiceLocation = dict["ServiceLocation"].ToString();
176 else
177 grec.GroupName = string.Empty;
178
179 if (dict.ContainsKey("ShownInList") && dict["ShownInList"] != null)
180 grec.ShowInList = bool.Parse(dict["ShownInList"].ToString());
181
182 if (dict.ContainsKey("MemberCount") && dict["MemberCount"] != null)
183 grec.MemberCount = Int32.Parse(dict["MemberCount"].ToString());
184
185 if (dict.ContainsKey("RoleCount") && dict["RoleCount"] != null)
186 grec.RoleCount = Int32.Parse(dict["RoleCount"].ToString());
187
188 return grec;
189 }
190
191 public static Dictionary<string, object> GroupMembershipData(ExtendedGroupMembershipData membership)
192 {
193 Dictionary<string, object> dict = new Dictionary<string, object>();
194 if (membership == null)
195 return dict;
196
197 dict["AcceptNotices"] = membership.AcceptNotices.ToString();
198 dict["AccessToken"] = Sanitize(membership.AccessToken);
199 dict["Active"] = membership.Active.ToString();
200 dict["ActiveRole"] = membership.ActiveRole.ToString();
201 dict["AllowPublish"] = membership.AllowPublish.ToString();
202 dict["Charter"] = Sanitize(membership.Charter);
203 dict["Contribution"] = membership.Contribution.ToString();
204 dict["FounderID"] = membership.FounderID.ToString();
205 dict["GroupID"] = membership.GroupID.ToString();
206 dict["GroupName"] = Sanitize(membership.GroupName);
207 dict["GroupPicture"] = membership.GroupPicture.ToString();
208 dict["GroupPowers"] = membership.GroupPowers.ToString();
209 dict["GroupTitle"] = Sanitize(membership.GroupTitle);
210 dict["ListInProfile"] = membership.ListInProfile.ToString();
211 dict["MaturePublish"] = membership.MaturePublish.ToString();
212 dict["MembershipFee"] = membership.MembershipFee.ToString();
213 dict["OpenEnrollment"] = membership.OpenEnrollment.ToString();
214 dict["ShowInList"] = membership.ShowInList.ToString();
215
216 return dict;
217 }
218
219 public static ExtendedGroupMembershipData GroupMembershipData(Dictionary<string, object> dict)
220 {
221 if (dict == null)
222 return null;
223
224 ExtendedGroupMembershipData membership = new ExtendedGroupMembershipData();
225
226 if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
227 membership.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
228
229 if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
230 membership.AccessToken = dict["AccessToken"].ToString();
231 else
232 membership.AccessToken = string.Empty;
233
234 if (dict.ContainsKey("Active") && dict["Active"] != null)
235 membership.Active = bool.Parse(dict["Active"].ToString());
236
237 if (dict.ContainsKey("ActiveRole") && dict["ActiveRole"] != null)
238 membership.ActiveRole = UUID.Parse(dict["ActiveRole"].ToString());
239
240 if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
241 membership.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
242
243 if (dict.ContainsKey("Charter") && dict["Charter"] != null)
244 membership.Charter = dict["Charter"].ToString();
245 else
246 membership.Charter = string.Empty;
247
248 if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
249 membership.Contribution = Int32.Parse(dict["Contribution"].ToString());
250
251 if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
252 membership.FounderID = UUID.Parse(dict["FounderID"].ToString());
253
254 if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
255 membership.GroupID = UUID.Parse(dict["GroupID"].ToString());
256
257 if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
258 membership.GroupName = dict["GroupName"].ToString();
259 else
260 membership.GroupName = string.Empty;
261
262 if (dict.ContainsKey("GroupPicture") && dict["GroupPicture"] != null)
263 membership.GroupPicture = UUID.Parse(dict["GroupPicture"].ToString());
264
265 if (dict.ContainsKey("GroupPowers") && dict["GroupPowers"] != null)
266 membership.GroupPowers = UInt64.Parse(dict["GroupPowers"].ToString());
267
268 if (dict.ContainsKey("GroupTitle") && dict["GroupTitle"] != null)
269 membership.GroupTitle = dict["GroupTitle"].ToString();
270 else
271 membership.GroupTitle = string.Empty;
272
273 if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
274 membership.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
275
276 if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
277 membership.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
278
279 if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
280 membership.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
281
282 if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
283 membership.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
284
285 if (dict.ContainsKey("ShowInList") && dict["ShowInList"] != null)
286 membership.ShowInList = bool.Parse(dict["ShowInList"].ToString());
287
288 return membership;
289 }
290
291 public static Dictionary<string, object> GroupMembersData(ExtendedGroupMembersData member)
292 {
293 Dictionary<string, object> dict = new Dictionary<string, object>();
294
295 dict["AcceptNotices"] = member.AcceptNotices.ToString();
296 dict["AccessToken"] = Sanitize(member.AccessToken);
297 dict["AgentID"] = Sanitize(member.AgentID);
298 dict["AgentPowers"] = member.AgentPowers.ToString();
299 dict["Contribution"] = member.Contribution.ToString();
300 dict["IsOwner"] = member.IsOwner.ToString();
301 dict["ListInProfile"] = member.ListInProfile.ToString();
302 dict["OnlineStatus"] = Sanitize(member.OnlineStatus);
303 dict["Title"] = Sanitize(member.Title);
304
305 return dict;
306 }
307
308 public static ExtendedGroupMembersData GroupMembersData(Dictionary<string, object> dict)
309 {
310 ExtendedGroupMembersData member = new ExtendedGroupMembersData();
311
312 if (dict == null)
313 return member;
314
315 if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
316 member.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
317
318 if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
319 member.AccessToken = Sanitize(dict["AccessToken"].ToString());
320 else
321 member.AccessToken = string.Empty;
322
323 if (dict.ContainsKey("AgentID") && dict["AgentID"] != null)
324 member.AgentID = Sanitize(dict["AgentID"].ToString());
325 else
326 member.AgentID = UUID.Zero.ToString();
327
328 if (dict.ContainsKey("AgentPowers") && dict["AgentPowers"] != null)
329 member.AgentPowers = UInt64.Parse(dict["AgentPowers"].ToString());
330
331 if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
332 member.Contribution = Int32.Parse(dict["Contribution"].ToString());
333
334 if (dict.ContainsKey("IsOwner") && dict["IsOwner"] != null)
335 member.IsOwner = bool.Parse(dict["IsOwner"].ToString());
336
337 if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
338 member.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
339
340 if (dict.ContainsKey("OnlineStatus") && dict["OnlineStatus"] != null)
341 member.OnlineStatus = Sanitize(dict["OnlineStatus"].ToString());
342 else
343 member.OnlineStatus = string.Empty;
344
345 if (dict.ContainsKey("Title") && dict["Title"] != null)
346 member.Title = Sanitize(dict["Title"].ToString());
347 else
348 member.Title = string.Empty;
349
350 return member;
351 }
352
353 public static Dictionary<string, object> GroupRolesData(GroupRolesData role)
354 {
355 Dictionary<string, object> dict = new Dictionary<string, object>();
356
357 dict["Description"] = Sanitize(role.Description);
358 dict["Members"] = role.Members.ToString();
359 dict["Name"] = Sanitize(role.Name);
360 dict["Powers"] = role.Powers.ToString();
361 dict["RoleID"] = role.RoleID.ToString();
362 dict["Title"] = Sanitize(role.Title);
363
364 return dict;
365 }
366
367 public static GroupRolesData GroupRolesData(Dictionary<string, object> dict)
368 {
369 GroupRolesData role = new GroupRolesData();
370
371 if (dict == null)
372 return role;
373
374 if (dict.ContainsKey("Description") && dict["Description"] != null)
375 role.Description = Sanitize(dict["Description"].ToString());
376 else
377 role.Description = string.Empty;
378
379 if (dict.ContainsKey("Members") && dict["Members"] != null)
380 role.Members = Int32.Parse(dict["Members"].ToString());
381
382 if (dict.ContainsKey("Name") && dict["Name"] != null)
383 role.Name = Sanitize(dict["Name"].ToString());
384 else
385 role.Name = string.Empty;
386
387 if (dict.ContainsKey("Powers") && dict["Powers"] != null)
388 role.Powers = UInt64.Parse(dict["Powers"].ToString());
389
390 if (dict.ContainsKey("Title") && dict["Title"] != null)
391 role.Title = Sanitize(dict["Title"].ToString());
392 else
393 role.Title = string.Empty;
394
395 if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
396 role.RoleID = UUID.Parse(dict["RoleID"].ToString());
397
398 return role;
399 }
400
401 public static Dictionary<string, object> GroupRoleMembersData(ExtendedGroupRoleMembersData rmember)
402 {
403 Dictionary<string, object> dict = new Dictionary<string, object>();
404
405 dict["RoleID"] = rmember.RoleID.ToString();
406 dict["MemberID"] = rmember.MemberID;
407 return dict;
408 }
409
410 public static ExtendedGroupRoleMembersData GroupRoleMembersData(Dictionary<string, object> dict)
411 {
412 ExtendedGroupRoleMembersData rmember = new ExtendedGroupRoleMembersData();
413
414 if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
415 rmember.RoleID = new UUID(dict["RoleID"].ToString());
416
417 if (dict.ContainsKey("MemberID") && dict["MemberID"] != null)
418 rmember.MemberID = dict["MemberID"].ToString();
419
420 return rmember;
421 }
422
423 public static Dictionary<string, object> GroupInviteInfo(GroupInviteInfo invite)
424 {
425 Dictionary<string, object> dict = new Dictionary<string, object>();
426
427 dict["InviteID"] = invite.InviteID.ToString();
428 dict["GroupID"] = invite.GroupID.ToString();
429 dict["RoleID"] = invite.RoleID.ToString();
430 dict["AgentID"] = invite.AgentID;
431
432 return dict;
433 }
434
435 public static GroupInviteInfo GroupInviteInfo(Dictionary<string, object> dict)
436 {
437 if (dict == null)
438 return null;
439
440 GroupInviteInfo invite = new GroupInviteInfo();
441
442 invite.InviteID = new UUID(dict["InviteID"].ToString());
443 invite.GroupID = new UUID(dict["GroupID"].ToString());
444 invite.RoleID = new UUID(dict["RoleID"].ToString());
445 invite.AgentID = Sanitize(dict["AgentID"].ToString());
446
447 return invite;
448 }
449
450 public static Dictionary<string, object> GroupNoticeData(ExtendedGroupNoticeData notice)
451 {
452 Dictionary<string, object> dict = new Dictionary<string, object>();
453
454 dict["NoticeID"] = notice.NoticeID.ToString();
455 dict["Timestamp"] = notice.Timestamp.ToString();
456 dict["FromName"] = Sanitize(notice.FromName);
457 dict["Subject"] = Sanitize(notice.Subject);
458 dict["HasAttachment"] = notice.HasAttachment.ToString();
459 dict["AttachmentItemID"] = notice.AttachmentItemID.ToString();
460 dict["AttachmentName"] = Sanitize(notice.AttachmentName);
461 dict["AttachmentType"] = notice.AttachmentType.ToString();
462 dict["AttachmentOwnerID"] = Sanitize(notice.AttachmentOwnerID);
463
464 return dict;
465 }
466
467 public static ExtendedGroupNoticeData GroupNoticeData(Dictionary<string, object> dict)
468 {
469 ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData();
470
471 if (dict == null)
472 return notice;
473
474 notice.NoticeID = new UUID(dict["NoticeID"].ToString());
475 notice.Timestamp = UInt32.Parse(dict["Timestamp"].ToString());
476 notice.FromName = Sanitize(dict["FromName"].ToString());
477 notice.Subject = Sanitize(dict["Subject"].ToString());
478 notice.HasAttachment = bool.Parse(dict["HasAttachment"].ToString());
479 notice.AttachmentItemID = new UUID(dict["AttachmentItemID"].ToString());
480 notice.AttachmentName = dict["AttachmentName"].ToString();
481 notice.AttachmentType = byte.Parse(dict["AttachmentType"].ToString());
482 notice.AttachmentOwnerID = dict["AttachmentOwnerID"].ToString();
483
484 return notice;
485 }
486
487 public static Dictionary<string, object> GroupNoticeInfo(GroupNoticeInfo notice)
488 {
489 Dictionary<string, object> dict = GroupNoticeData(notice.noticeData);
490
491 dict["GroupID"] = notice.GroupID.ToString();
492 dict["Message"] = Sanitize(notice.Message);
493
494 return dict;
495 }
496
497 public static GroupNoticeInfo GroupNoticeInfo(Dictionary<string, object> dict)
498 {
499 GroupNoticeInfo notice = new GroupNoticeInfo();
500
501 notice.noticeData = GroupNoticeData(dict);
502 notice.GroupID = new UUID(dict["GroupID"].ToString());
503 notice.Message = Sanitize(dict["Message"].ToString());
504
505 return notice;
506 }
507 }
508
509}
diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs
new file mode 100644
index 0000000..d172d48
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs
@@ -0,0 +1,594 @@
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 Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
42
43namespace OpenSim.Groups
44{
45 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsMessagingModule")]
46 public class GroupsMessagingModule : ISharedRegionModule, IGroupsMessagingModule
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private List<Scene> m_sceneList = new List<Scene>();
51 private IPresenceService m_presenceService;
52
53 private IMessageTransferModule m_msgTransferModule = null;
54
55 private IGroupsServicesConnector m_groupData = null;
56
57 // Config Options
58 private bool m_groupMessagingEnabled = false;
59 private bool m_debugEnabled = true;
60
61 /// <summary>
62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information.
63 /// </summary>
64 private bool m_messageOnlineAgentsOnly;
65
66 /// <summary>
67 /// Cache for online users.
68 /// </summary>
69 /// <remarks>
70 /// Group ID is key, presence information for online members is value.
71 /// Will only be non-null if m_messageOnlineAgentsOnly = true
72 /// We cache here so that group messages don't constantly have to re-request the online user list to avoid
73 /// attempted expensive sending of messages to offline users.
74 /// The tradeoff is that a user that comes online will not receive messages consistently from all other users
75 /// until caches have updated.
76 /// Therefore, we set the cache expiry to just 20 seconds.
77 /// </remarks>
78 private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache;
79
80 private int m_usersOnlineCacheExpirySeconds = 20;
81
82 #region Region Module interfaceBase Members
83
84 public void Initialise(IConfigSource config)
85 {
86 IConfig groupsConfig = config.Configs["Groups"];
87
88 if (groupsConfig == null)
89 // Do not run this module by default.
90 return;
91
92 // if groups aren't enabled, we're not needed.
93 // if we're not specified as the connector to use, then we're not wanted
94 if ((groupsConfig.GetBoolean("Enabled", false) == false)
95 || (groupsConfig.GetString("MessagingModule", "") != Name))
96 {
97 m_groupMessagingEnabled = false;
98 return;
99 }
100
101 m_groupMessagingEnabled = groupsConfig.GetBoolean("MessagingEnabled", true);
102
103 if (!m_groupMessagingEnabled)
104 return;
105
106 m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
107
108 if (m_messageOnlineAgentsOnly)
109 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
110
111 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true);
112
113 m_log.InfoFormat(
114 "[Groups.Messaging]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}",
115 m_messageOnlineAgentsOnly, m_debugEnabled);
116 }
117
118 public void AddRegion(Scene scene)
119 {
120 if (!m_groupMessagingEnabled)
121 return;
122
123 scene.RegisterModuleInterface<IGroupsMessagingModule>(this);
124 m_sceneList.Add(scene);
125
126 scene.EventManager.OnNewClient += OnNewClient;
127 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
128 scene.EventManager.OnClientLogin += OnClientLogin;
129 }
130
131 public void RegionLoaded(Scene scene)
132 {
133 if (!m_groupMessagingEnabled)
134 return;
135
136 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
137
138 m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
139
140 // No groups module, no groups messaging
141 if (m_groupData == null)
142 {
143 m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled.");
144 RemoveRegion(scene);
145 return;
146 }
147
148 m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
149
150 // No message transfer module, no groups messaging
151 if (m_msgTransferModule == null)
152 {
153 m_log.Error("[Groups.Messaging]: Could not get MessageTransferModule");
154 RemoveRegion(scene);
155 return;
156 }
157
158 if (m_presenceService == null)
159 m_presenceService = scene.PresenceService;
160
161 }
162
163 public void RemoveRegion(Scene scene)
164 {
165 if (!m_groupMessagingEnabled)
166 return;
167
168 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
169
170 m_sceneList.Remove(scene);
171 scene.EventManager.OnNewClient -= OnNewClient;
172 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
173 scene.EventManager.OnClientLogin -= OnClientLogin;
174 scene.UnregisterModuleInterface<IGroupsMessagingModule>(this);
175 }
176
177 public void Close()
178 {
179 if (!m_groupMessagingEnabled)
180 return;
181
182 if (m_debugEnabled) m_log.Debug("[Groups.Messaging]: Shutting down GroupsMessagingModule module.");
183
184 m_sceneList.Clear();
185
186 m_groupData = null;
187 m_msgTransferModule = null;
188 }
189
190 public Type ReplaceableInterface
191 {
192 get { return null; }
193 }
194
195 public string Name
196 {
197 get { return "Groups Messaging Module V2"; }
198 }
199
200 public void PostInitialise()
201 {
202 // NoOp
203 }
204
205 #endregion
206
207
208 /// <summary>
209 /// Not really needed, but does confirm that the group exists.
210 /// </summary>
211 public bool StartGroupChatSession(UUID agentID, UUID groupID)
212 {
213 if (m_debugEnabled)
214 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
215
216 GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
217
218 if (groupInfo != null)
219 {
220 return true;
221 }
222 else
223 {
224 return false;
225 }
226 }
227
228 public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
229 {
230 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID).ToString(), groupID);
231 int groupMembersCount = groupMembers.Count;
232
233 if (m_messageOnlineAgentsOnly)
234 {
235 string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
236
237 // We cache in order not to overwhlem the presence service on large grids with many groups. This does
238 // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed.
239 // (assuming this is the same across all grid simulators).
240 PresenceInfo[] onlineAgents;
241 if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents))
242 {
243 onlineAgents = m_presenceService.GetAgents(t1);
244 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
245 }
246
247 HashSet<string> onlineAgentsUuidSet = new HashSet<string>();
248 Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID));
249
250 groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
251
252 // if (m_debugEnabled)
253// m_log.DebugFormat(
254// "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
255// groupID, groupMembersCount, groupMembers.Count());
256 }
257 else
258 {
259 if (m_debugEnabled)
260 m_log.DebugFormat(
261 "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members",
262 groupID, groupMembers.Count);
263 }
264
265 int requestStartTick = Environment.TickCount;
266
267 foreach (GroupMembersData member in groupMembers)
268 {
269 if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID))
270 {
271 // Don't deliver messages to people who have dropped this session
272 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID);
273 continue;
274 }
275
276 // Copy Message
277 GridInstantMessage msg = new GridInstantMessage();
278 msg.imSessionID = groupID.Guid;
279 msg.fromAgentName = im.fromAgentName;
280 msg.message = im.message;
281 msg.dialog = im.dialog;
282 msg.offline = im.offline;
283 msg.ParentEstateID = im.ParentEstateID;
284 msg.Position = im.Position;
285 msg.RegionID = im.RegionID;
286 msg.binaryBucket = im.binaryBucket;
287 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
288
289 msg.fromAgentID = im.fromAgentID;
290 msg.fromGroup = true;
291
292 msg.toAgentID = member.AgentID.Guid;
293
294 IClientAPI client = GetActiveClient(member.AgentID);
295 if (client == null)
296 {
297 // If they're not local, forward across the grid
298 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID);
299 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
300 }
301 else
302 {
303 // Deliver locally, directly
304 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name);
305 ProcessMessageFromGroupSession(msg);
306 }
307 }
308
309 // Temporary for assessing how long it still takes to send messages to large online groups.
310 if (m_messageOnlineAgentsOnly)
311 m_log.DebugFormat(
312 "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms",
313 groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick);
314 }
315
316 #region SimGridEventHandlers
317
318 void OnClientLogin(IClientAPI client)
319 {
320 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
321 }
322
323 private void OnNewClient(IClientAPI client)
324 {
325 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
326
327 client.OnInstantMessage += OnInstantMessage;
328 }
329
330 private void OnGridInstantMessage(GridInstantMessage msg)
331 {
332 // The instant message module will only deliver messages of dialog types:
333 // MessageFromAgent, StartTyping, StopTyping, MessageFromObject
334 //
335 // Any other message type will not be delivered to a client by the
336 // Instant Message Module
337
338
339 if (m_debugEnabled)
340 {
341 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
342
343 DebugGridInstantMessage(msg);
344 }
345
346 // Incoming message from a group
347 if ((msg.fromGroup == true) &&
348 ((msg.dialog == (byte)InstantMessageDialog.SessionSend)
349 || (msg.dialog == (byte)InstantMessageDialog.SessionAdd)
350 || (msg.dialog == (byte)InstantMessageDialog.SessionDrop)))
351 {
352 ProcessMessageFromGroupSession(msg);
353 }
354 }
355
356 private void ProcessMessageFromGroupSession(GridInstantMessage msg)
357 {
358 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID);
359
360 UUID AgentID = new UUID(msg.fromAgentID);
361 UUID GroupID = new UUID(msg.imSessionID);
362
363 switch (msg.dialog)
364 {
365 case (byte)InstantMessageDialog.SessionAdd:
366 m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
367 break;
368
369 case (byte)InstantMessageDialog.SessionDrop:
370 m_groupData.AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID);
371 break;
372
373 case (byte)InstantMessageDialog.SessionSend:
374 if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)
375 && !m_groupData.hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)
376 )
377 {
378 // Agent not in session and hasn't dropped from session
379 // Add them to the session for now, and Invite them
380 m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
381
382 UUID toAgentID = new UUID(msg.toAgentID);
383 IClientAPI activeClient = GetActiveClient(toAgentID);
384 if (activeClient != null)
385 {
386 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
387 if (groupInfo != null)
388 {
389 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message");
390
391 // Force? open the group session dialog???
392 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg);
393 IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>();
394 eq.ChatterboxInvitation(
395 GroupID
396 , groupInfo.GroupName
397 , new UUID(msg.fromAgentID)
398 , msg.message
399 , new UUID(msg.toAgentID)
400 , msg.fromAgentName
401 , msg.dialog
402 , msg.timestamp
403 , msg.offline == 1
404 , (int)msg.ParentEstateID
405 , msg.Position
406 , 1
407 , new UUID(msg.imSessionID)
408 , msg.fromGroup
409 , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName)
410 );
411
412 eq.ChatterBoxSessionAgentListUpdates(
413 new UUID(GroupID)
414 , new UUID(msg.fromAgentID)
415 , new UUID(msg.toAgentID)
416 , false //canVoiceChat
417 , false //isModerator
418 , false //text mute
419 );
420 }
421 }
422 }
423 else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID))
424 {
425 // User hasn't dropped, so they're in the session,
426 // maybe we should deliver it.
427 IClientAPI client = GetActiveClient(new UUID(msg.toAgentID));
428 if (client != null)
429 {
430 // Deliver locally, directly
431 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name);
432 client.SendInstantMessage(msg);
433 }
434 else
435 {
436 m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
437 }
438 }
439 break;
440
441 default:
442 m_log.WarnFormat("[Groups.Messaging]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString());
443 break;
444 }
445 }
446
447 #endregion
448
449
450 #region ClientEvents
451 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
452 {
453 if (m_debugEnabled)
454 {
455 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
456
457 DebugGridInstantMessage(im);
458 }
459
460 // Start group IM session
461 if ((im.dialog == (byte)InstantMessageDialog.SessionGroupStart))
462 {
463 if (m_debugEnabled) m_log.InfoFormat("[Groups.Messaging]: imSessionID({0}) toAgentID({1})", im.imSessionID, im.toAgentID);
464
465 UUID GroupID = new UUID(im.imSessionID);
466 UUID AgentID = new UUID(im.fromAgentID);
467
468 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
469
470 if (groupInfo != null)
471 {
472 m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
473
474 ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID);
475
476 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
477 queue.ChatterBoxSessionAgentListUpdates(
478 GroupID
479 , AgentID
480 , new UUID(im.toAgentID)
481 , false //canVoiceChat
482 , false //isModerator
483 , false //text mute
484 );
485 }
486 }
487
488 // Send a message from locally connected client to a group
489 if ((im.dialog == (byte)InstantMessageDialog.SessionSend))
490 {
491 UUID GroupID = new UUID(im.imSessionID);
492 UUID AgentID = new UUID(im.fromAgentID);
493
494 if (m_debugEnabled)
495 m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString());
496
497 //If this agent is sending a message, then they want to be in the session
498 m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
499
500 SendMessageToGroup(im, GroupID);
501 }
502 }
503
504 #endregion
505
506 void ChatterBoxSessionStartReplyViaCaps(IClientAPI remoteClient, string groupName, UUID groupID)
507 {
508 if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
509
510 OSDMap moderatedMap = new OSDMap(4);
511 moderatedMap.Add("voice", OSD.FromBoolean(false));
512
513 OSDMap sessionMap = new OSDMap(4);
514 sessionMap.Add("moderated_mode", moderatedMap);
515 sessionMap.Add("session_name", OSD.FromString(groupName));
516 sessionMap.Add("type", OSD.FromInteger(0));
517 sessionMap.Add("voice_enabled", OSD.FromBoolean(false));
518
519 OSDMap bodyMap = new OSDMap(4);
520 bodyMap.Add("session_id", OSD.FromUUID(groupID));
521 bodyMap.Add("temp_session_id", OSD.FromUUID(groupID));
522 bodyMap.Add("success", OSD.FromBoolean(true));
523 bodyMap.Add("session_info", sessionMap);
524
525 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
526
527 if (queue != null)
528 {
529 queue.Enqueue(queue.BuildEvent("ChatterBoxSessionStartReply", bodyMap), remoteClient.AgentId);
530 }
531 }
532
533 private void DebugGridInstantMessage(GridInstantMessage im)
534 {
535 // Don't log any normal IMs (privacy!)
536 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent)
537 {
538 m_log.WarnFormat("[Groups.Messaging]: IM: fromGroup({0})", im.fromGroup ? "True" : "False");
539 m_log.WarnFormat("[Groups.Messaging]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString());
540 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentID({0})", im.fromAgentID.ToString());
541 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentName({0})", im.fromAgentName.ToString());
542 m_log.WarnFormat("[Groups.Messaging]: IM: imSessionID({0})", im.imSessionID.ToString());
543 m_log.WarnFormat("[Groups.Messaging]: IM: message({0})", im.message.ToString());
544 m_log.WarnFormat("[Groups.Messaging]: IM: offline({0})", im.offline.ToString());
545 m_log.WarnFormat("[Groups.Messaging]: IM: toAgentID({0})", im.toAgentID.ToString());
546 m_log.WarnFormat("[Groups.Messaging]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket"));
547 }
548 }
549
550 #region Client Tools
551
552 /// <summary>
553 /// Try to find an active IClientAPI reference for agentID giving preference to root connections
554 /// </summary>
555 private IClientAPI GetActiveClient(UUID agentID)
556 {
557 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Looking for local client {0}", agentID);
558
559 IClientAPI child = null;
560
561 // Try root avatar first
562 foreach (Scene scene in m_sceneList)
563 {
564 ScenePresence sp = scene.GetScenePresence(agentID);
565 if (sp != null)
566 {
567 if (!sp.IsChildAgent)
568 {
569 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name);
570 return sp.ControllingClient;
571 }
572 else
573 {
574 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name);
575 child = sp.ControllingClient;
576 }
577 }
578 }
579
580 // If we didn't find a root, then just return whichever child we found, or null if none
581 if (child == null)
582 {
583 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Could not find local client for agent : {0}", agentID);
584 }
585 else
586 {
587 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Returning child agent for client : {0}", child.Name);
588 }
589 return child;
590 }
591
592 #endregion
593 }
594}
diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs
new file mode 100644
index 0000000..10bfa8f
--- /dev/null
+++ b/OpenSim/Addons/Groups/GroupsModule.cs
@@ -0,0 +1,1467 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
42
43namespace OpenSim.Groups
44{
45 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsModule")]
46 public class GroupsModule : ISharedRegionModule, IGroupsModule
47 {
48 /// <summary>
49 /// </summary>
50
51 private static readonly ILog m_log =
52 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private List<Scene> m_sceneList = new List<Scene>();
55
56 private IMessageTransferModule m_msgTransferModule = null;
57
58 private IGroupsServicesConnector m_groupData = null;
59 private IUserManagement m_UserManagement;
60
61 // Configuration settings
62 private bool m_groupsEnabled = false;
63 private bool m_groupNoticesEnabled = true;
64 private bool m_debugEnabled = false;
65 private int m_levelGroupCreate = 0;
66
67 #region Region Module interfaceBase Members
68
69 public void Initialise(IConfigSource config)
70 {
71 IConfig groupsConfig = config.Configs["Groups"];
72
73 if (groupsConfig == null)
74 {
75 // Do not run this module by default.
76 return;
77 }
78 else
79 {
80 m_groupsEnabled = groupsConfig.GetBoolean("Enabled", false);
81 if (!m_groupsEnabled)
82 {
83 return;
84 }
85
86 if (groupsConfig.GetString("Module", "Default") != Name)
87 {
88 m_groupsEnabled = false;
89
90 return;
91 }
92
93 m_log.InfoFormat("[Groups]: Initializing {0}", this.Name);
94
95 m_groupNoticesEnabled = groupsConfig.GetBoolean("NoticesEnabled", true);
96 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", false);
97 m_levelGroupCreate = groupsConfig.GetInt("LevelGroupCreate", 0);
98 }
99 }
100
101 public void AddRegion(Scene scene)
102 {
103 if (m_groupsEnabled)
104 {
105 scene.RegisterModuleInterface<IGroupsModule>(this);
106 scene.AddCommand(
107 "debug",
108 this,
109 "debug groups verbose",
110 "debug groups verbose <true|false>",
111 "This setting turns on very verbose groups debugging",
112 HandleDebugGroupsVerbose);
113 }
114 }
115
116 private void HandleDebugGroupsVerbose(object modules, string[] args)
117 {
118 if (args.Length < 4)
119 {
120 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
121 return;
122 }
123
124 bool verbose = false;
125 if (!bool.TryParse(args[3], out verbose))
126 {
127 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
128 return;
129 }
130
131 m_debugEnabled = verbose;
132
133 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
134 }
135
136 public void RegionLoaded(Scene scene)
137 {
138 if (!m_groupsEnabled)
139 return;
140
141 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
142
143 scene.EventManager.OnNewClient += OnNewClient;
144 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
145 // The InstantMessageModule itself doesn't do this,
146 // so lets see if things explode if we don't do it
147 // scene.EventManager.OnClientClosed += OnClientClosed;
148
149 if (m_groupData == null)
150 {
151 m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
152
153 // No Groups Service Connector, then nothing works...
154 if (m_groupData == null)
155 {
156 m_groupsEnabled = false;
157 m_log.Error("[Groups]: Could not get IGroupsServicesConnector");
158 RemoveRegion(scene);
159 return;
160 }
161 }
162
163 if (m_msgTransferModule == null)
164 {
165 m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
166
167 // No message transfer module, no notices, group invites, rejects, ejects, etc
168 if (m_msgTransferModule == null)
169 {
170 m_log.Warn("[Groups]: Could not get MessageTransferModule");
171 }
172 }
173
174 if (m_UserManagement == null)
175 {
176 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
177 if (m_UserManagement == null)
178 m_log.Warn("[Groups]: Could not get UserManagementModule");
179 }
180
181 lock (m_sceneList)
182 {
183 m_sceneList.Add(scene);
184 }
185
186
187 }
188
189 public void RemoveRegion(Scene scene)
190 {
191 if (!m_groupsEnabled)
192 return;
193
194 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
195
196 scene.EventManager.OnNewClient -= OnNewClient;
197 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
198
199 lock (m_sceneList)
200 {
201 m_sceneList.Remove(scene);
202 }
203 }
204
205 public void Close()
206 {
207 if (!m_groupsEnabled)
208 return;
209
210 if (m_debugEnabled) m_log.Debug("[Groups]: Shutting down Groups module.");
211 }
212
213 public Type ReplaceableInterface
214 {
215 get { return null; }
216 }
217
218 public string Name
219 {
220 get { return "Groups Module V2"; }
221 }
222
223 public void PostInitialise()
224 {
225 // NoOp
226 }
227
228 #endregion
229
230 #region EventHandlers
231 private void OnNewClient(IClientAPI client)
232 {
233 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
234
235 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
236 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
237 client.OnDirFindQuery += OnDirFindQuery;
238 client.OnRequestAvatarProperties += OnRequestAvatarProperties;
239
240 // Used for Notices and Group Invites/Accept/Reject
241 client.OnInstantMessage += OnInstantMessage;
242
243 // Send client their groups information.
244 SendAgentGroupDataUpdate(client, client.AgentId);
245 }
246
247 private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
248 {
249 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
250
251 //GroupMembershipData[] avatarGroups = m_groupData.GetAgentGroupMemberships(GetRequestingAgentID(remoteClient), avatarID).ToArray();
252 GroupMembershipData[] avatarGroups = GetProfileListedGroupMemberships(remoteClient, avatarID);
253 remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups);
254 }
255
256 /*
257 * This becomes very problematic in a shared module. In a shared module you may have more then one
258 * reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections.
259 * The OnClientClosed event does not provide anything to indicate which one of those should be closed
260 * nor does it provide what scene it was from so that the specific reference can be looked up.
261 * The InstantMessageModule.cs does not currently worry about unregistering the handles,
262 * and it should be an issue, since it's the client that references us not the other way around
263 * , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed
264 private void OnClientClosed(UUID AgentId)
265 {
266 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
267
268 lock (m_ActiveClients)
269 {
270 if (m_ActiveClients.ContainsKey(AgentId))
271 {
272 IClientAPI client = m_ActiveClients[AgentId];
273 client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
274 client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest;
275 client.OnDirFindQuery -= OnDirFindQuery;
276 client.OnInstantMessage -= OnInstantMessage;
277
278 m_ActiveClients.Remove(AgentId);
279 }
280 else
281 {
282 if (m_debugEnabled) m_log.WarnFormat("[Groups]: Client closed that wasn't registered here.");
283 }
284
285
286 }
287 }
288 */
289
290 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
291 {
292 if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
293 {
294 if (m_debugEnabled)
295 m_log.DebugFormat(
296 "[Groups]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
297 System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
298
299 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
300 remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), queryText).ToArray());
301 }
302
303 }
304
305 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
306 {
307 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
308
309 UUID activeGroupID = UUID.Zero;
310 string activeGroupTitle = string.Empty;
311 string activeGroupName = string.Empty;
312 ulong activeGroupPowers = (ulong)GroupPowers.None;
313
314 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(GetRequestingAgentIDStr(remoteClient), dataForAgentID.ToString());
315 if (membership != null)
316 {
317 activeGroupID = membership.GroupID;
318 activeGroupTitle = membership.GroupTitle;
319 activeGroupPowers = membership.GroupPowers;
320 }
321
322 SendAgentDataUpdate(remoteClient, dataForAgentID, activeGroupID, activeGroupName, activeGroupPowers, activeGroupTitle);
323
324 SendScenePresenceUpdate(dataForAgentID, activeGroupTitle);
325 }
326
327 private void HandleUUIDGroupNameRequest(UUID GroupID, IClientAPI remoteClient)
328 {
329 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
330
331 string GroupName;
332
333 GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null);
334 if (group != null)
335 {
336 GroupName = group.GroupName;
337 }
338 else
339 {
340 GroupName = "Unknown";
341 }
342
343 remoteClient.SendGroupNameReply(GroupID, GroupName);
344 }
345
346 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
347 {
348 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
349
350 m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog);
351 // Group invitations
352 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
353 {
354 UUID inviteID = new UUID(im.imSessionID);
355 GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
356
357 if (inviteInfo == null)
358 {
359 if (m_debugEnabled) m_log.WarnFormat("[Groups]: Received an Invite IM for an invite that does not exist {0}.", inviteID);
360 return;
361 }
362
363 //m_log.DebugFormat("[XXX]: Invite is for Agent {0} to Group {1}.", inviteInfo.AgentID, inviteInfo.GroupID);
364
365 UUID fromAgentID = new UUID(im.fromAgentID);
366 UUID invitee = UUID.Zero;
367 string tmp = string.Empty;
368 Util.ParseUniversalUserIdentifier(inviteInfo.AgentID, out invitee, out tmp, out tmp, out tmp, out tmp);
369 if ((inviteInfo != null) && (fromAgentID == invitee))
370 {
371 // Accept
372 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept)
373 {
374 //m_log.DebugFormat("[XXX]: Received an accept invite notice.");
375
376 // and the sessionid is the role
377 string reason = string.Empty;
378 if (!m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), invitee.ToString(), inviteInfo.GroupID, inviteInfo.RoleID, string.Empty, out reason))
379 remoteClient.SendAgentAlertMessage("Unable to add you to the group: " + reason, false);
380 else
381 {
382 GridInstantMessage msg = new GridInstantMessage();
383 msg.imSessionID = UUID.Zero.Guid;
384 msg.fromAgentID = UUID.Zero.Guid;
385 msg.toAgentID = invitee.Guid;
386 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
387 msg.fromAgentName = "Groups";
388 msg.message = string.Format("You have been added to the group.");
389 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageBox;
390 msg.fromGroup = false;
391 msg.offline = (byte)0;
392 msg.ParentEstateID = 0;
393 msg.Position = Vector3.Zero;
394 msg.RegionID = UUID.Zero.Guid;
395 msg.binaryBucket = new byte[0];
396
397 OutgoingInstantMessage(msg, invitee);
398
399 UpdateAllClientsWithGroupInfo(invitee);
400 }
401
402 m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
403
404 }
405
406 // Reject
407 if (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)
408 {
409 if (m_debugEnabled) m_log.DebugFormat("[Groups]: Received a reject invite notice.");
410 m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID);
411
412 m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), inviteInfo.AgentID, inviteInfo.GroupID);
413 }
414 }
415 }
416
417 // Group notices
418 if ((im.dialog == (byte)InstantMessageDialog.GroupNotice))
419 {
420 if (!m_groupNoticesEnabled)
421 {
422 return;
423 }
424
425 UUID GroupID = new UUID(im.toAgentID);
426 if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null) != null)
427 {
428 UUID NoticeID = UUID.Random();
429 string Subject = im.message.Substring(0, im.message.IndexOf('|'));
430 string Message = im.message.Substring(Subject.Length + 1);
431
432 InventoryItemBase item = null;
433 bool hasAttachment = false;
434
435 if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
436 {
437 hasAttachment = true;
438 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
439 binBucket = binBucket.Remove(0, 14).Trim();
440
441 OSD binBucketOSD = OSDParser.DeserializeLLSDXml(binBucket);
442 if (binBucketOSD is OSDMap)
443 {
444 OSDMap binBucketMap = (OSDMap)binBucketOSD;
445
446 UUID itemID = binBucketMap["item_id"].AsUUID();
447 UUID ownerID = binBucketMap["owner_id"].AsUUID();
448 item = new InventoryItemBase(itemID, ownerID);
449 item = m_sceneList[0].InventoryService.GetItem(item);
450 }
451 else
452 m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
453 }
454
455 if (m_groupData.AddGroupNotice(GetRequestingAgentIDStr(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message,
456 hasAttachment,
457 (byte)(item == null ? 0 : item.AssetType),
458 item == null ? null : item.Name,
459 item == null ? UUID.Zero : item.ID,
460 item == null ? UUID.Zero.ToString() : item.Owner.ToString()))
461 {
462 if (OnNewGroupNotice != null)
463 {
464 OnNewGroupNotice(GroupID, NoticeID);
465 }
466
467 // Send notice out to everyone that wants notices
468 // Build notice IIM
469 GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
470 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID))
471 {
472 if (member.AcceptNotices)
473 {
474 msg.toAgentID = member.AgentID.Guid;
475 OutgoingInstantMessage(msg, member.AgentID);
476 }
477 }
478 }
479 }
480 }
481
482 if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
483 {
484 if (im.binaryBucket.Length < 16) // Invalid
485 return;
486
487 //// 16 bytes are the UUID. Maybe.
488 UUID folderID = new UUID(im.binaryBucket, 0);
489 UUID noticeID = new UUID(im.imSessionID);
490
491 GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID);
492 if (notice != null)
493 {
494 UUID giver = new UUID(im.toAgentID);
495 string tmp = string.Empty;
496 Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out giver, out tmp, out tmp, out tmp, out tmp);
497
498 m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
499 InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
500 giver, notice.noticeData.AttachmentItemID);
501
502 if (itemCopy == null)
503 {
504 remoteClient.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
505 return;
506 }
507
508 remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
509 }
510
511 }
512
513 // Interop, received special 210 code for ejecting a group member
514 // this only works within the comms servers domain, and won't work hypergrid
515 // TODO:FIXME: Use a presense server of some kind to find out where the
516 // client actually is, and try contacting that region directly to notify them,
517 // or provide the notification via xmlrpc update queue
518 if ((im.dialog == 210))
519 {
520 // This is sent from the region that the ejectee was ejected from
521 // if it's being delivered here, then the ejectee is here
522 // so we need to send local updates to the agent.
523
524 UUID ejecteeID = new UUID(im.toAgentID);
525
526 im.dialog = (byte)InstantMessageDialog.MessageFromAgent;
527 OutgoingInstantMessage(im, ejecteeID);
528
529 IClientAPI ejectee = GetActiveClient(ejecteeID);
530 if (ejectee != null)
531 {
532 UUID groupID = new UUID(im.imSessionID);
533 ejectee.SendAgentDropGroup(groupID);
534 }
535 }
536 }
537
538 private void OnGridInstantMessage(GridInstantMessage msg)
539 {
540 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
541
542 // Trigger the above event handler
543 OnInstantMessage(null, msg);
544
545 // If a message from a group arrives here, it may need to be forwarded to a local client
546 if (msg.fromGroup == true)
547 {
548 switch (msg.dialog)
549 {
550 case (byte)InstantMessageDialog.GroupInvitation:
551 case (byte)InstantMessageDialog.GroupNotice:
552 UUID toAgentID = new UUID(msg.toAgentID);
553 IClientAPI localClient = GetActiveClient(toAgentID);
554 if (localClient != null)
555 {
556 localClient.SendInstantMessage(msg);
557 }
558 break;
559 }
560 }
561 }
562
563 #endregion
564
565 #region IGroupsModule Members
566
567 public event NewGroupNotice OnNewGroupNotice;
568
569 public GroupRecord GetGroupRecord(UUID GroupID)
570 {
571 return m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
572 }
573
574 public GroupRecord GetGroupRecord(string name)
575 {
576 return m_groupData.GetGroupRecord(UUID.Zero.ToString(), UUID.Zero, name);
577 }
578
579 public void ActivateGroup(IClientAPI remoteClient, UUID groupID)
580 {
581 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
582
583 m_groupData.SetAgentActiveGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
584
585 // Changing active group changes title, active powers, all kinds of things
586 // anyone who is in any region that can see this client, should probably be
587 // updated with new group info. At a minimum, they should get ScenePresence
588 // updated with new title.
589 UpdateAllClientsWithGroupInfo(remoteClient.AgentId);
590 }
591
592 /// <summary>
593 /// Get the Role Titles for an Agent, for a specific group
594 /// </summary>
595 public List<GroupTitlesData> GroupTitlesRequest(IClientAPI remoteClient, UUID groupID)
596 {
597 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
598
599 List<GroupRolesData> agentRoles = m_groupData.GetAgentGroupRoles(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
600 GroupMembershipData agentMembership = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
601
602 List<GroupTitlesData> titles = new List<GroupTitlesData>();
603 foreach (GroupRolesData role in agentRoles)
604 {
605 GroupTitlesData title = new GroupTitlesData();
606 title.Name = role.Name;
607 if (agentMembership != null)
608 {
609 title.Selected = agentMembership.ActiveRole == role.RoleID;
610 }
611 title.UUID = role.RoleID;
612
613 titles.Add(title);
614 }
615
616 return titles;
617 }
618
619 public List<GroupMembersData> GroupMembersRequest(IClientAPI remoteClient, UUID groupID)
620 {
621 if (m_debugEnabled)
622 m_log.DebugFormat(
623 "[Groups]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name);
624
625 List<GroupMembersData> data = m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), groupID);
626
627 if (m_debugEnabled)
628 {
629 foreach (GroupMembersData member in data)
630 {
631 m_log.DebugFormat("[Groups]: Member({0}) - IsOwner({1})", member.AgentID, member.IsOwner);
632 }
633 }
634
635 return data;
636
637 }
638
639 public List<GroupRolesData> GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID)
640 {
641 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
642
643 List<GroupRolesData> data = m_groupData.GetGroupRoles(GetRequestingAgentIDStr(remoteClient), groupID);
644
645 return data;
646 }
647
648 public List<GroupRoleMembersData> GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID)
649 {
650 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
651
652 List<GroupRoleMembersData> data = m_groupData.GetGroupRoleMembers(GetRequestingAgentIDStr(remoteClient), groupID);
653
654 if (m_debugEnabled)
655 {
656 foreach (GroupRoleMembersData member in data)
657 {
658 m_log.DebugFormat("[Groups]: Member({0}) - Role({1})", member.MemberID, member.RoleID);
659 }
660 }
661 return data;
662 }
663
664 public GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID)
665 {
666 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
667
668 GroupProfileData profile = new GroupProfileData();
669
670 // just to get the OwnerRole...
671 ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), groupID, string.Empty);
672 GroupMembershipData memberInfo = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
673 if (groupInfo != null)
674 {
675 profile.AllowPublish = groupInfo.AllowPublish;
676 profile.Charter = groupInfo.Charter;
677 profile.FounderID = groupInfo.FounderID;
678 profile.GroupID = groupID;
679 profile.GroupMembershipCount = groupInfo.MemberCount;
680 profile.GroupRolesCount = groupInfo.RoleCount;
681 profile.InsigniaID = groupInfo.GroupPicture;
682 profile.MaturePublish = groupInfo.MaturePublish;
683 profile.MembershipFee = groupInfo.MembershipFee;
684 profile.Money = 0;
685 profile.Name = groupInfo.GroupName;
686 profile.OpenEnrollment = groupInfo.OpenEnrollment;
687 profile.OwnerRole = groupInfo.OwnerRoleID;
688 profile.ShowInList = groupInfo.ShowInList;
689 }
690 if (memberInfo != null)
691 {
692 profile.MemberTitle = memberInfo.GroupTitle;
693 profile.PowersMask = memberInfo.GroupPowers;
694 }
695
696 return profile;
697 }
698
699 public GroupMembershipData[] GetMembershipData(UUID agentID)
700 {
701 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
702
703 return m_groupData.GetAgentGroupMemberships(UUID.Zero.ToString(), agentID.ToString()).ToArray();
704 }
705
706 public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID)
707 {
708 if (m_debugEnabled)
709 m_log.DebugFormat(
710 "[Groups]: {0} called with groupID={1}, agentID={2}",
711 System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID);
712
713 return m_groupData.GetAgentGroupMembership(UUID.Zero.ToString(), agentID.ToString(), groupID);
714 }
715
716 public void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
717 {
718 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
719
720 // Note: Permissions checking for modification rights is handled by the Groups Server/Service
721 string reason = string.Empty;
722 if (!m_groupData.UpdateGroup(GetRequestingAgentIDStr(remoteClient), groupID, charter, showInList, insigniaID, membershipFee,
723 openEnrollment, allowPublish, maturePublish, out reason))
724 remoteClient.SendAgentAlertMessage(reason, false);
725 }
726
727 public void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile)
728 {
729 // Note: Permissions checking for modification rights is handled by the Groups Server/Service
730 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
731
732 m_groupData.UpdateMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, acceptNotices, listInProfile);
733 }
734
735 public UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
736 {
737 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called in {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Scene.RegionInfo.RegionName);
738
739 if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), UUID.Zero, name) != null)
740 {
741 remoteClient.SendCreateGroupReply(UUID.Zero, false, "A group with the same name already exists.");
742 return UUID.Zero;
743 }
744
745 // check user level
746 ScenePresence avatar = null;
747 Scene scene = (Scene)remoteClient.Scene;
748 scene.TryGetScenePresence(remoteClient.AgentId, out avatar);
749
750 if (avatar != null)
751 {
752 if (avatar.UserLevel < m_levelGroupCreate)
753 {
754 remoteClient.SendCreateGroupReply(UUID.Zero, false, String.Format("Insufficient permissions to create a group. Requires level {0}", m_levelGroupCreate));
755 return UUID.Zero;
756 }
757 }
758
759 // check funds
760 // is there is a money module present ?
761 IMoneyModule money = scene.RequestModuleInterface<IMoneyModule>();
762 if (money != null)
763 {
764 // do the transaction, that is if the agent has got sufficient funds
765 if (!money.AmountCovered(remoteClient.AgentId, money.GroupCreationCharge)) {
766 remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group.");
767 return UUID.Zero;
768 }
769 money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, "Group Creation");
770 }
771 string reason = string.Empty;
772 UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment,
773 allowPublish, maturePublish, remoteClient.AgentId, out reason);
774
775 if (groupID != UUID.Zero)
776 {
777 remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly");
778
779 // Update the founder with new group information.
780 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
781 }
782 else
783 remoteClient.SendCreateGroupReply(groupID, false, reason);
784
785 return groupID;
786 }
787
788 public GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID)
789 {
790 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
791
792 // ToDo: check if agent is a member of group and is allowed to see notices?
793
794 List<ExtendedGroupNoticeData> notices = m_groupData.GetGroupNotices(GetRequestingAgentIDStr(remoteClient), groupID);
795 List<GroupNoticeData> os_notices = new List<GroupNoticeData>();
796 foreach (ExtendedGroupNoticeData n in notices)
797 {
798 GroupNoticeData osn = n.ToGroupNoticeData();
799 os_notices.Add(osn);
800 }
801
802 return os_notices.ToArray();
803 }
804
805 /// <summary>
806 /// Get the title of the agent's current role.
807 /// </summary>
808 public string GetGroupTitle(UUID avatarID)
809 {
810 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
811
812 GroupMembershipData membership = m_groupData.GetAgentActiveMembership(UUID.Zero.ToString(), avatarID.ToString());
813 if (membership != null)
814 {
815 return membership.GroupTitle;
816 }
817 return string.Empty;
818 }
819
820 /// <summary>
821 /// Change the current Active Group Role for Agent
822 /// </summary>
823 public void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID)
824 {
825 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
826
827 m_groupData.SetAgentActiveGroupRole(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, titleRoleID);
828
829 // TODO: Not sure what all is needed here, but if the active group role change is for the group
830 // the client currently has set active, then we need to do a scene presence update too
831 // if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID)
832
833 UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient));
834 }
835
836
837 public void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType)
838 {
839 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
840
841 // Security Checks are handled in the Groups Service.
842
843 switch ((OpenMetaverse.GroupRoleUpdate)updateType)
844 {
845 case OpenMetaverse.GroupRoleUpdate.Create:
846 string reason = string.Empty;
847 if (!m_groupData.AddGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, UUID.Random(), name, description, title, powers, out reason))
848 remoteClient.SendAgentAlertMessage("Unable to create role: " + reason, false);
849 break;
850
851 case OpenMetaverse.GroupRoleUpdate.Delete:
852 m_groupData.RemoveGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID);
853 break;
854
855 case OpenMetaverse.GroupRoleUpdate.UpdateAll:
856 case OpenMetaverse.GroupRoleUpdate.UpdateData:
857 case OpenMetaverse.GroupRoleUpdate.UpdatePowers:
858 if (m_debugEnabled)
859 {
860 GroupPowers gp = (GroupPowers)powers;
861 m_log.DebugFormat("[Groups]: Role ({0}) updated with Powers ({1}) ({2})", name, powers.ToString(), gp.ToString());
862 }
863 m_groupData.UpdateGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID, name, description, title, powers);
864 break;
865
866 case OpenMetaverse.GroupRoleUpdate.NoUpdate:
867 default:
868 // No Op
869 break;
870
871 }
872
873 // TODO: This update really should send out updates for everyone in the role that just got changed.
874 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
875 }
876
877 public void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes)
878 {
879 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
880 // Todo: Security check
881
882 switch (changes)
883 {
884 case 0:
885 // Add
886 m_groupData.AddAgentToGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
887
888 break;
889 case 1:
890 // Remove
891 m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID);
892
893 break;
894 default:
895 m_log.ErrorFormat("[Groups]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes);
896 break;
897 }
898
899 // TODO: This update really should send out updates for everyone in the role that just got changed.
900 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
901 }
902
903 public void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID)
904 {
905 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID);
906
907 //GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null);
908
909 GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
910 //GridInstantMessage msg = new GridInstantMessage();
911 //msg.imSessionID = UUID.Zero.Guid;
912 //msg.fromAgentID = data.GroupID.Guid;
913 //msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
914 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
915 //msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
916 //msg.message = data.noticeData.Subject + "|" + data.Message;
917 //msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
918 //msg.fromGroup = true;
919 //msg.offline = (byte)0;
920 //msg.ParentEstateID = 0;
921 //msg.Position = Vector3.Zero;
922 //msg.RegionID = UUID.Zero.Guid;
923 //msg.binaryBucket = data.BinaryBucket;
924
925 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
926 }
927
928 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
929 {
930 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
931
932 GridInstantMessage msg = new GridInstantMessage();
933 byte[] bucket;
934
935 msg.imSessionID = groupNoticeID.Guid;
936 msg.toAgentID = agentID.Guid;
937 msg.dialog = dialog;
938 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
939 msg.fromGroup = true;
940 msg.offline = (byte)0;
941 msg.ParentEstateID = 0;
942 msg.Position = Vector3.Zero;
943 msg.RegionID = UUID.Zero.Guid;
944
945 GroupNoticeInfo info = m_groupData.GetGroupNotice(agentID.ToString(), groupNoticeID);
946 if (info != null)
947 {
948 msg.fromAgentID = info.GroupID.Guid;
949 msg.timestamp = info.noticeData.Timestamp;
950 msg.fromAgentName = info.noticeData.FromName;
951 msg.message = info.noticeData.Subject + "|" + info.Message;
952 if (info.noticeData.HasAttachment)
953 {
954 byte[] name = System.Text.Encoding.UTF8.GetBytes(info.noticeData.AttachmentName);
955 bucket = new byte[19 + name.Length];
956 bucket[0] = 1; // has attachment?
957 bucket[1] = info.noticeData.AttachmentType; // attachment type
958 name.CopyTo(bucket, 18);
959 }
960 else
961 {
962 bucket = new byte[19];
963 bucket[0] = 0; // Has att?
964 bucket[1] = 0; // type
965 bucket[18] = 0; // null terminated
966 }
967
968 info.GroupID.ToBytes(bucket, 2);
969 msg.binaryBucket = bucket;
970 }
971 else
972 {
973 m_log.DebugFormat("[Groups]: Group Notice {0} not found, composing empty message.", groupNoticeID);
974 msg.fromAgentID = UUID.Zero.Guid;
975 msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ;
976 msg.fromAgentName = string.Empty;
977 msg.message = string.Empty;
978 msg.binaryBucket = new byte[0];
979 }
980
981 return msg;
982 }
983
984 public void SendAgentGroupDataUpdate(IClientAPI remoteClient)
985 {
986 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
987
988 // Send agent information about his groups
989 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
990 }
991
992 public void JoinGroupRequest(IClientAPI remoteClient, UUID groupID)
993 {
994 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
995
996 string reason = string.Empty;
997 // Should check to see if OpenEnrollment, or if there's an outstanding invitation
998 if (m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, UUID.Zero, string.Empty, out reason))
999 {
1000
1001 remoteClient.SendJoinGroupReply(groupID, true);
1002
1003 // Should this send updates to everyone in the group?
1004 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
1005 }
1006 else
1007 remoteClient.SendJoinGroupReply(groupID, false);
1008 }
1009
1010 public void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID)
1011 {
1012 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1013
1014 m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID);
1015
1016 remoteClient.SendLeaveGroupReply(groupID, true);
1017
1018 remoteClient.SendAgentDropGroup(groupID);
1019
1020 // SL sends out notifcations to the group messaging session that the person has left
1021 // Should this also update everyone who is in the group?
1022 SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
1023 }
1024
1025 public void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID)
1026 {
1027 EjectGroupMember(remoteClient, GetRequestingAgentID(remoteClient), groupID, ejecteeID);
1028 }
1029
1030 public void EjectGroupMember(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID ejecteeID)
1031 {
1032 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1033
1034 // Todo: Security check?
1035 m_groupData.RemoveAgentFromGroup(agentID.ToString(), ejecteeID.ToString(), groupID);
1036
1037 string agentName;
1038 RegionInfo regionInfo;
1039
1040 // remoteClient provided or just agentID?
1041 if (remoteClient != null)
1042 {
1043 agentName = remoteClient.Name;
1044 regionInfo = remoteClient.Scene.RegionInfo;
1045 remoteClient.SendEjectGroupMemberReply(agentID, groupID, true);
1046 }
1047 else
1048 {
1049 IClientAPI client = GetActiveClient(agentID);
1050
1051 if (client != null)
1052 {
1053 agentName = client.Name;
1054 regionInfo = client.Scene.RegionInfo;
1055 client.SendEjectGroupMemberReply(agentID, groupID, true);
1056 }
1057 else
1058 {
1059 regionInfo = m_sceneList[0].RegionInfo;
1060 UserAccount acc = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, agentID);
1061
1062 if (acc != null)
1063 {
1064 agentName = acc.FirstName + " " + acc.LastName;
1065 }
1066 else
1067 {
1068 agentName = "Unknown member";
1069 }
1070 }
1071 }
1072
1073 GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1074
1075 UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, ejecteeID);
1076 if ((groupInfo == null) || (account == null))
1077 {
1078 return;
1079 }
1080
1081 // Send Message to Ejectee
1082 GridInstantMessage msg = new GridInstantMessage();
1083
1084 msg.imSessionID = UUID.Zero.Guid;
1085 msg.fromAgentID = agentID.Guid;
1086 // msg.fromAgentID = info.GroupID;
1087 msg.toAgentID = ejecteeID.Guid;
1088 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1089 msg.timestamp = 0;
1090 msg.fromAgentName = agentName;
1091 msg.message = string.Format("You have been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName);
1092 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageFromAgent;
1093 msg.fromGroup = false;
1094 msg.offline = (byte)0;
1095 msg.ParentEstateID = 0;
1096 msg.Position = Vector3.Zero;
1097 msg.RegionID = regionInfo.RegionID.Guid;
1098 msg.binaryBucket = new byte[0];
1099 OutgoingInstantMessage(msg, ejecteeID);
1100
1101 // Message to ejector
1102 // Interop, received special 210 code for ejecting a group member
1103 // this only works within the comms servers domain, and won't work hypergrid
1104 // TODO:FIXME: Use a presense server of some kind to find out where the
1105 // client actually is, and try contacting that region directly to notify them,
1106 // or provide the notification via xmlrpc update queue
1107
1108 msg = new GridInstantMessage();
1109 msg.imSessionID = UUID.Zero.Guid;
1110 msg.fromAgentID = agentID.Guid;
1111 msg.toAgentID = agentID.Guid;
1112 msg.timestamp = 0;
1113 msg.fromAgentName = agentName;
1114 if (account != null)
1115 {
1116 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, account.FirstName + " " + account.LastName);
1117 }
1118 else
1119 {
1120 msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, "Unknown member");
1121 }
1122 msg.dialog = (byte)210; //interop
1123 msg.fromGroup = false;
1124 msg.offline = (byte)0;
1125 msg.ParentEstateID = 0;
1126 msg.Position = Vector3.Zero;
1127 msg.RegionID = regionInfo.RegionID.Guid;
1128 msg.binaryBucket = new byte[0];
1129 OutgoingInstantMessage(msg, agentID);
1130
1131
1132 // SL sends out messages to everyone in the group
1133 // Who all should receive updates and what should they be updated with?
1134 UpdateAllClientsWithGroupInfo(ejecteeID);
1135 }
1136
1137 public void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID)
1138 {
1139 InviteGroup(remoteClient, GetRequestingAgentID(remoteClient), groupID, invitedAgentID, roleID);
1140 }
1141
1142 public void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID invitedAgentID, UUID roleID)
1143 {
1144 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1145
1146 string agentName = m_UserManagement.GetUserName(agentID);
1147 RegionInfo regionInfo = m_sceneList[0].RegionInfo;
1148
1149 GroupRecord group = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
1150 if (group == null)
1151 {
1152 m_log.DebugFormat("[Groups]: No such group {0}", groupID);
1153 return;
1154 }
1155
1156 // Todo: Security check, probably also want to send some kind of notification
1157 UUID InviteID = UUID.Random();
1158
1159 if (m_groupData.AddAgentToGroupInvite(agentID.ToString(), InviteID, groupID, roleID, invitedAgentID.ToString()))
1160 {
1161 if (m_msgTransferModule != null)
1162 {
1163 Guid inviteUUID = InviteID.Guid;
1164
1165 GridInstantMessage msg = new GridInstantMessage();
1166
1167 msg.imSessionID = inviteUUID;
1168
1169 // msg.fromAgentID = agentID.Guid;
1170 msg.fromAgentID = groupID.Guid;
1171 msg.toAgentID = invitedAgentID.Guid;
1172 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1173 msg.timestamp = 0;
1174 msg.fromAgentName = agentName;
1175 msg.message = string.Format("{0} has invited you to join a group called {1}. There is no cost to join this group.", agentName, group.GroupName);
1176 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
1177 msg.fromGroup = true;
1178 msg.offline = (byte)0;
1179 msg.ParentEstateID = 0;
1180 msg.Position = Vector3.Zero;
1181 msg.RegionID = regionInfo.RegionID.Guid;
1182 msg.binaryBucket = new byte[20];
1183
1184 OutgoingInstantMessage(msg, invitedAgentID);
1185 }
1186 }
1187 }
1188
1189 #endregion
1190
1191 #region Client/Update Tools
1192
1193 /// <summary>
1194 /// Try to find an active IClientAPI reference for agentID giving preference to root connections
1195 /// </summary>
1196 private IClientAPI GetActiveClient(UUID agentID)
1197 {
1198 IClientAPI child = null;
1199
1200 // Try root avatar first
1201 foreach (Scene scene in m_sceneList)
1202 {
1203 ScenePresence sp = scene.GetScenePresence(agentID);
1204 if (sp != null)
1205 {
1206 if (!sp.IsChildAgent)
1207 {
1208 return sp.ControllingClient;
1209 }
1210 else
1211 {
1212 child = sp.ControllingClient;
1213 }
1214 }
1215 }
1216
1217 // If we didn't find a root, then just return whichever child we found, or null if none
1218 return child;
1219 }
1220
1221 /// <summary>
1222 /// Send 'remoteClient' the group membership 'data' for agent 'dataForAgentID'.
1223 /// </summary>
1224 private void SendGroupMembershipInfoViaCaps(IClientAPI remoteClient, UUID dataForAgentID, GroupMembershipData[] data)
1225 {
1226 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1227
1228 OSDArray AgentData = new OSDArray(1);
1229 OSDMap AgentDataMap = new OSDMap(1);
1230 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
1231 AgentData.Add(AgentDataMap);
1232
1233
1234 OSDArray GroupData = new OSDArray(data.Length);
1235 OSDArray NewGroupData = new OSDArray(data.Length);
1236
1237 foreach (GroupMembershipData membership in data)
1238 {
1239 if (GetRequestingAgentID(remoteClient) != dataForAgentID)
1240 {
1241 if (!membership.ListInProfile)
1242 {
1243 // If we're sending group info to remoteclient about another agent,
1244 // filter out groups the other agent doesn't want to share.
1245 continue;
1246 }
1247 }
1248
1249 OSDMap GroupDataMap = new OSDMap(6);
1250 OSDMap NewGroupDataMap = new OSDMap(1);
1251
1252 GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID));
1253 GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers));
1254 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices));
1255 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture));
1256 GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution));
1257 GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName));
1258 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile));
1259
1260 GroupData.Add(GroupDataMap);
1261 NewGroupData.Add(NewGroupDataMap);
1262 }
1263
1264 OSDMap llDataStruct = new OSDMap(3);
1265 llDataStruct.Add("AgentData", AgentData);
1266 llDataStruct.Add("GroupData", GroupData);
1267 llDataStruct.Add("NewGroupData", NewGroupData);
1268
1269 if (m_debugEnabled)
1270 {
1271 m_log.InfoFormat("[Groups]: {0}", OSDParser.SerializeJsonString(llDataStruct));
1272 }
1273
1274 IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
1275
1276 if (queue != null)
1277 {
1278 queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient));
1279 }
1280
1281 }
1282
1283 private void SendScenePresenceUpdate(UUID AgentID, string Title)
1284 {
1285 if (m_debugEnabled) m_log.DebugFormat("[Groups]: Updating scene title for {0} with title: {1}", AgentID, Title);
1286
1287 ScenePresence presence = null;
1288
1289 foreach (Scene scene in m_sceneList)
1290 {
1291 presence = scene.GetScenePresence(AgentID);
1292 if (presence != null)
1293 {
1294 if (presence.Grouptitle != Title)
1295 {
1296 presence.Grouptitle = Title;
1297
1298 if (! presence.IsChildAgent)
1299 presence.SendAvatarDataToAllAgents();
1300 }
1301 }
1302 }
1303 }
1304
1305 /// <summary>
1306 /// Send updates to all clients who might be interested in groups data for dataForClientID
1307 /// </summary>
1308 private void UpdateAllClientsWithGroupInfo(UUID dataForClientID)
1309 {
1310 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1311
1312 // TODO: Probably isn't nessesary to update every client in every scene.
1313 // Need to examine client updates and do only what's nessesary.
1314 lock (m_sceneList)
1315 {
1316 foreach (Scene scene in m_sceneList)
1317 {
1318 scene.ForEachClient(delegate(IClientAPI client) { SendAgentGroupDataUpdate(client, dataForClientID); });
1319 }
1320 }
1321 }
1322
1323 /// <summary>
1324 /// Update remoteClient with group information about dataForAgentID
1325 /// </summary>
1326 private void SendAgentGroupDataUpdate(IClientAPI remoteClient, UUID dataForAgentID)
1327 {
1328 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called for {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name);
1329
1330 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1331
1332 OnAgentDataUpdateRequest(remoteClient, dataForAgentID, UUID.Zero);
1333
1334 // Need to send a group membership update to the client
1335 // UDP version doesn't seem to behave nicely. But we're going to send it out here
1336 // with an empty group membership to hopefully remove groups being displayed due
1337 // to the core Groups Stub
1338 //remoteClient.SendGroupMembership(new GroupMembershipData[0]);
1339
1340 GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID);
1341 SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray);
1342 //remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray);
1343 if (remoteClient.AgentId == dataForAgentID)
1344 remoteClient.RefreshGroupMembership();
1345 }
1346
1347 /// <summary>
1348 /// Get a list of groups memberships for the agent that are marked "ListInProfile"
1349 /// (unless that agent has a godLike aspect, in which case get all groups)
1350 /// </summary>
1351 /// <param name="dataForAgentID"></param>
1352 /// <returns></returns>
1353 private GroupMembershipData[] GetProfileListedGroupMemberships(IClientAPI requestingClient, UUID dataForAgentID)
1354 {
1355 List<GroupMembershipData> membershipData = m_groupData.GetAgentGroupMemberships(requestingClient.AgentId.ToString(), dataForAgentID.ToString());
1356 GroupMembershipData[] membershipArray;
1357
1358 // cScene and property accessor 'isGod' are in support of the opertions to bypass 'hidden' group attributes for
1359 // those with a GodLike aspect.
1360 Scene cScene = (Scene)requestingClient.Scene;
1361 bool isGod = cScene.Permissions.IsGod(requestingClient.AgentId);
1362
1363 if (isGod)
1364 {
1365 membershipArray = membershipData.ToArray();
1366 }
1367 else
1368 {
1369 if (requestingClient.AgentId != dataForAgentID)
1370 {
1371 Predicate<GroupMembershipData> showInProfile = delegate(GroupMembershipData membership)
1372 {
1373 return membership.ListInProfile;
1374 };
1375
1376 membershipArray = membershipData.FindAll(showInProfile).ToArray();
1377 }
1378 else
1379 {
1380 membershipArray = membershipData.ToArray();
1381 }
1382 }
1383
1384 if (m_debugEnabled)
1385 {
1386 m_log.InfoFormat("[Groups]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId);
1387 foreach (GroupMembershipData membership in membershipArray)
1388 {
1389 m_log.InfoFormat("[Groups]: {0} :: {1} - {2} - {3}", dataForAgentID, membership.GroupName, membership.GroupTitle, membership.GroupPowers);
1390 }
1391 }
1392
1393 return membershipArray;
1394 }
1395
1396
1397 private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle)
1398 {
1399 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1400
1401 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1402 UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID);
1403 string firstname, lastname;
1404 if (account != null)
1405 {
1406 firstname = account.FirstName;
1407 lastname = account.LastName;
1408 }
1409 else
1410 {
1411 firstname = "Unknown";
1412 lastname = "Unknown";
1413 }
1414
1415 remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
1416 lastname, activeGroupPowers, activeGroupName,
1417 activeGroupTitle);
1418 }
1419
1420 #endregion
1421
1422 #region IM Backed Processes
1423
1424 private void OutgoingInstantMessage(GridInstantMessage msg, UUID msgTo)
1425 {
1426 if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1427
1428 IClientAPI localClient = GetActiveClient(msgTo);
1429 if (localClient != null)
1430 {
1431 if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is local, delivering directly", localClient.Name);
1432 localClient.SendInstantMessage(msg);
1433 }
1434 else if (m_msgTransferModule != null)
1435 {
1436 if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is not local, delivering via TransferModule", msgTo);
1437 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: Message Sent: {0}", success?"Succeeded":"Failed"); });
1438 }
1439 }
1440
1441 public void NotifyChange(UUID groupID)
1442 {
1443 // Notify all group members of a chnge in group roles and/or
1444 // permissions
1445 //
1446 }
1447
1448 #endregion
1449
1450 private string GetRequestingAgentIDStr(IClientAPI client)
1451 {
1452 return GetRequestingAgentID(client).ToString();
1453 }
1454
1455 private UUID GetRequestingAgentID(IClientAPI client)
1456 {
1457 UUID requestingAgentID = UUID.Zero;
1458 if (client != null)
1459 {
1460 requestingAgentID = client.AgentId;
1461 }
1462 return requestingAgentID;
1463 }
1464
1465 }
1466
1467}
diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs
new file mode 100644
index 0000000..59fec6f
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs
@@ -0,0 +1,289 @@
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;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36
37using OpenMetaverse;
38using log4net;
39
40namespace OpenSim.Groups
41{
42 public class GroupsServiceHGConnector
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private string m_ServerURI;
47 private object m_Lock = new object();
48
49 public GroupsServiceHGConnector(string url)
50 {
51 m_ServerURI = url;
52 if (!m_ServerURI.EndsWith("/"))
53 m_ServerURI += "/";
54
55 m_log.DebugFormat("[Groups.HGConnector]: Groups server at {0}", m_ServerURI);
56 }
57
58 public bool CreateProxy(string RequestingAgentID, string AgentID, string accessToken, UUID groupID, string url, string name, out string reason)
59 {
60 reason = string.Empty;
61
62 Dictionary<string, object> sendData = new Dictionary<string,object>();
63 sendData["RequestingAgentID"] = RequestingAgentID;
64 sendData["AgentID"] = AgentID.ToString();
65 sendData["AccessToken"] = accessToken;
66 sendData["GroupID"] = groupID.ToString();
67 sendData["Location"] = url;
68 sendData["Name"] = name;
69 Dictionary<string, object> ret = MakeRequest("POSTGROUP", sendData);
70
71 if (ret == null)
72 return false;
73
74 if (!ret.ContainsKey("RESULT"))
75 return false;
76
77 if (ret["RESULT"].ToString().ToLower() != "true")
78 {
79 reason = ret["REASON"].ToString();
80 return false;
81 }
82
83 return true;
84
85 }
86
87 public void RemoveAgentFromGroup(string AgentID, UUID GroupID, string token)
88 {
89 Dictionary<string, object> sendData = new Dictionary<string, object>();
90 sendData["AgentID"] = AgentID;
91 sendData["GroupID"] = GroupID.ToString();
92 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
93 MakeRequest("REMOVEAGENTFROMGROUP", sendData);
94 }
95
96 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, string token)
97 {
98 if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
99 return null;
100
101 Dictionary<string, object> sendData = new Dictionary<string, object>();
102 if (GroupID != UUID.Zero)
103 sendData["GroupID"] = GroupID.ToString();
104 if (GroupName != null && GroupName != string.Empty)
105 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
106
107 sendData["RequestingAgentID"] = RequestingAgentID;
108 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
109
110 Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
111
112 if (ret == null)
113 return null;
114
115 if (!ret.ContainsKey("RESULT"))
116 return null;
117
118 if (ret["RESULT"].ToString() == "NULL")
119 return null;
120
121 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
122 }
123
124 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
125 {
126 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
127
128 Dictionary<string, object> sendData = new Dictionary<string, object>();
129 sendData["GroupID"] = GroupID.ToString();
130 sendData["RequestingAgentID"] = RequestingAgentID;
131 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
132 Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
133
134 if (ret == null)
135 return members;
136
137 if (!ret.ContainsKey("RESULT"))
138 return members;
139
140 if (ret["RESULT"].ToString() == "NULL")
141 return members;
142 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
143 {
144 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
145 members.Add(m);
146 }
147
148 return members;
149 }
150
151 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
152 {
153 List<GroupRolesData> roles = new List<GroupRolesData>();
154
155 Dictionary<string, object> sendData = new Dictionary<string, object>();
156 sendData["GroupID"] = GroupID.ToString();
157 sendData["RequestingAgentID"] = RequestingAgentID;
158 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
159 Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
160
161 if (ret == null)
162 return roles;
163
164 if (!ret.ContainsKey("RESULT"))
165 return roles;
166
167 if (ret["RESULT"].ToString() == "NULL")
168 return roles;
169 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
170 {
171 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
172 roles.Add(m);
173 }
174
175 return roles;
176 }
177
178 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
179 {
180 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
181
182 Dictionary<string, object> sendData = new Dictionary<string, object>();
183 sendData["GroupID"] = GroupID.ToString();
184 sendData["RequestingAgentID"] = RequestingAgentID;
185 sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
186 Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
187
188 if (ret == null)
189 return rmembers;
190
191 if (!ret.ContainsKey("RESULT"))
192 return rmembers;
193
194 if (ret["RESULT"].ToString() == "NULL")
195 return rmembers;
196
197 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
198 {
199 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
200 rmembers.Add(m);
201 }
202
203 return rmembers;
204 }
205
206 public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
207 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
208 {
209 Dictionary<string, object> sendData = new Dictionary<string, object>();
210 sendData["GroupID"] = groupID.ToString();
211 sendData["NoticeID"] = noticeID.ToString();
212 sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
213 sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
214 sendData["Message"] = GroupsDataUtils.Sanitize(message);
215 sendData["HasAttachment"] = hasAttachment.ToString();
216 if (hasAttachment)
217 {
218 sendData["AttachmentType"] = attType.ToString();
219 sendData["AttachmentName"] = attName.ToString();
220 sendData["AttachmentItemID"] = attItemID.ToString();
221 sendData["AttachmentOwnerID"] = attOwnerID;
222 }
223 sendData["RequestingAgentID"] = RequestingAgentID;
224
225 Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
226
227 if (ret == null)
228 return false;
229
230 if (!ret.ContainsKey("RESULT"))
231 return false;
232
233 if (ret["RESULT"].ToString().ToLower() != "true")
234 return false;
235
236 return true;
237 }
238
239 public bool VerifyNotice(UUID noticeID, UUID groupID)
240 {
241 Dictionary<string, object> sendData = new Dictionary<string, object>();
242 sendData["NoticeID"] = noticeID.ToString();
243 sendData["GroupID"] = groupID.ToString();
244 Dictionary<string, object> ret = MakeRequest("VERIFYNOTICE", sendData);
245
246 if (ret == null)
247 return false;
248
249 if (!ret.ContainsKey("RESULT"))
250 return false;
251
252 if (ret["RESULT"].ToString().ToLower() != "true")
253 return false;
254
255 return true;
256 }
257
258 //
259 //
260 //
261 //
262 //
263
264 #region Make Request
265
266 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
267 {
268 sendData["METHOD"] = method;
269
270 string reply = string.Empty;
271 lock (m_Lock)
272 reply = SynchronousRestFormsRequester.MakeRequest("POST",
273 m_ServerURI + "hg-groups",
274 ServerUtils.BuildQueryString(sendData));
275
276 //m_log.DebugFormat("[XXX]: reply was {0}", reply);
277
278 if (reply == string.Empty || reply == null)
279 return null;
280
281 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
282 reply);
283
284 return replyData;
285 }
286 #endregion
287
288 }
289}
diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
new file mode 100644
index 0000000..f670272
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs
@@ -0,0 +1,717 @@
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;
33
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Services.Interfaces;
39
40using OpenMetaverse;
41using Mono.Addins;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Groups
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceHGConnectorModule")]
48 public class GroupsServiceHGConnectorModule : ISharedRegionModule, IGroupsServicesConnector
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private bool m_Enabled = false;
53 private IGroupsServicesConnector m_LocalGroupsConnector;
54 private string m_LocalGroupsServiceLocation;
55 private IUserManagement m_UserManagement;
56 private IOfflineIMService m_OfflineIM;
57 private IMessageTransferModule m_Messaging;
58 private List<Scene> m_Scenes;
59 private ForeignImporter m_ForeignImporter;
60 private string m_ServiceLocation;
61 private IConfigSource m_Config;
62
63 private Dictionary<string, GroupsServiceHGConnector> m_NetworkConnectors = new Dictionary<string, GroupsServiceHGConnector>();
64 private RemoteConnectorCacheWrapper m_CacheWrapper; // for caching info of external group services
65
66 #region ISharedRegionModule
67
68 public void Initialise(IConfigSource config)
69 {
70 IConfig groupsConfig = config.Configs["Groups"];
71 if (groupsConfig == null)
72 return;
73
74 if ((groupsConfig.GetBoolean("Enabled", false) == false)
75 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
76 {
77 return;
78 }
79
80 m_Config = config;
81 m_ServiceLocation = groupsConfig.GetString("LocalService", "local"); // local or remote
82 m_LocalGroupsServiceLocation = groupsConfig.GetString("GroupsExternalURI", "http://127.0.0.1");
83 m_Scenes = new List<Scene>();
84
85 m_Enabled = true;
86
87 m_log.DebugFormat("[Groups]: Initializing {0} with LocalService {1}", this.Name, m_ServiceLocation);
88 }
89
90 public string Name
91 {
92 get { return "Groups HG Service Connector"; }
93 }
94
95 public Type ReplaceableInterface
96 {
97 get { return null; }
98 }
99
100 public void AddRegion(Scene scene)
101 {
102 if (!m_Enabled)
103 return;
104
105 m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
106 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
107 m_Scenes.Add(scene);
108
109 scene.EventManager.OnNewClient += OnNewClient;
110 }
111
112 public void RemoveRegion(Scene scene)
113 {
114 if (!m_Enabled)
115 return;
116
117 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
118 m_Scenes.Remove(scene);
119 }
120
121 public void RegionLoaded(Scene scene)
122 {
123 if (!m_Enabled)
124 return;
125
126 if (m_UserManagement == null)
127 {
128 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
129 m_OfflineIM = scene.RequestModuleInterface<IOfflineIMService>();
130 m_Messaging = scene.RequestModuleInterface<IMessageTransferModule>();
131 m_ForeignImporter = new ForeignImporter(m_UserManagement);
132
133 if (m_ServiceLocation.Equals("local"))
134 {
135 m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement);
136 // Also, if local, create the endpoint for the HGGroupsService
137 new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty,
138 scene.RequestModuleInterface<IOfflineIMService>(), scene.RequestModuleInterface<IUserAccountService>());
139
140 }
141 else
142 m_LocalGroupsConnector = new GroupsServiceRemoteConnectorModule(m_Config, m_UserManagement);
143
144 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
145 }
146
147 }
148
149 public void PostInitialise()
150 {
151 }
152
153 public void Close()
154 {
155 }
156
157 #endregion
158
159 private void OnNewClient(IClientAPI client)
160 {
161 client.OnCompleteMovementToRegion += OnCompleteMovementToRegion;
162 }
163
164 void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
165 {
166 object sp = null;
167 if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
168 {
169 if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc)
170 {
171 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
172 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 &&
173 m_OfflineIM != null && m_Messaging != null)
174 {
175 List<GridInstantMessage> ims = m_OfflineIM.GetMessages(aCircuit.AgentID);
176 if (ims != null && ims.Count > 0)
177 foreach (GridInstantMessage im in ims)
178 m_Messaging.SendInstantMessage(im, delegate(bool success) { });
179 }
180 }
181 }
182 }
183
184 #region IGroupsServicesConnector
185
186 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
187 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
188 {
189 m_log.DebugFormat("[Groups]: Creating group {0}", name);
190 reason = string.Empty;
191 if (m_UserManagement.IsLocalGridUser(RequestingAgentID))
192 return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID,
193 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
194 else
195 {
196 reason = "Only local grid users are allowed to create a new group";
197 return UUID.Zero;
198 }
199 }
200
201 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
202 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
203 {
204 reason = string.Empty;
205 string url = string.Empty;
206 string name = string.Empty;
207 if (IsLocal(groupID, out url, out name))
208 return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee,
209 openEnrollment, allowPublish, maturePublish, out reason);
210 else
211 {
212 reason = "Changes to remote group not allowed. Please go to the group's original world.";
213 return false;
214 }
215 }
216
217 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
218 {
219 string url = string.Empty;
220 string name = string.Empty;
221 if (IsLocal(GroupID, out url, out name))
222 return m_LocalGroupsConnector.GetGroupRecord(AgentUUI(RequestingAgentID), GroupID, GroupName);
223 else if (url != string.Empty)
224 {
225 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
226 string accessToken = string.Empty;
227 if (membership != null)
228 accessToken = membership.AccessToken;
229 else
230 return null;
231
232 GroupsServiceHGConnector c = GetConnector(url);
233 if (c != null)
234 {
235 ExtendedGroupRecord grec = m_CacheWrapper.GetGroupRecord(RequestingAgentID, GroupID, GroupName, delegate
236 {
237 return c.GetGroupRecord(AgentUUIForOutside(RequestingAgentID), GroupID, GroupName, accessToken);
238 });
239
240 if (grec != null)
241 ImportForeigner(grec.FounderUUI);
242 return grec;
243 }
244 }
245
246 return null;
247 }
248
249 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
250 {
251 return m_LocalGroupsConnector.FindGroups(AgentUUI(RequestingAgentID), search);
252 }
253
254 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
255 {
256 string url = string.Empty, gname = string.Empty;
257 if (IsLocal(GroupID, out url, out gname))
258 return m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), GroupID);
259 else if (!string.IsNullOrEmpty(url))
260 {
261 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
262 string accessToken = string.Empty;
263 if (membership != null)
264 accessToken = membership.AccessToken;
265 else
266 return null;
267
268 GroupsServiceHGConnector c = GetConnector(url);
269 if (c != null)
270 {
271 return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
272 {
273 return c.GetGroupMembers(AgentUUIForOutside(RequestingAgentID), GroupID, accessToken);
274 });
275
276 }
277 }
278 return new List<GroupMembersData>();
279 }
280
281 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
282 {
283 reason = string.Empty;
284 string url = string.Empty, gname = string.Empty;
285
286 if (IsLocal(groupID, out url, out gname))
287 return m_LocalGroupsConnector.AddGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers, out reason);
288 else
289 {
290 reason = "Operation not allowed outside this group's origin world.";
291 return false;
292 }
293 }
294
295 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
296 {
297 string url = string.Empty, gname = string.Empty;
298
299 if (IsLocal(groupID, out url, out gname))
300 return m_LocalGroupsConnector.UpdateGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers);
301 else
302 {
303 return false;
304 }
305
306 }
307
308 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
309 {
310 string url = string.Empty, gname = string.Empty;
311
312 if (IsLocal(groupID, out url, out gname))
313 m_LocalGroupsConnector.RemoveGroupRole(AgentUUI(RequestingAgentID), groupID, roleID);
314 else
315 {
316 return;
317 }
318 }
319
320 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID groupID)
321 {
322 string url = string.Empty, gname = string.Empty;
323
324 if (IsLocal(groupID, out url, out gname))
325 return m_LocalGroupsConnector.GetGroupRoles(AgentUUI(RequestingAgentID), groupID);
326 else if (!string.IsNullOrEmpty(url))
327 {
328 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
329 string accessToken = string.Empty;
330 if (membership != null)
331 accessToken = membership.AccessToken;
332 else
333 return null;
334
335 GroupsServiceHGConnector c = GetConnector(url);
336 if (c != null)
337 {
338 return m_CacheWrapper.GetGroupRoles(RequestingAgentID, groupID, delegate
339 {
340 return c.GetGroupRoles(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
341 });
342
343 }
344 }
345
346 return new List<GroupRolesData>();
347 }
348
349 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID groupID)
350 {
351 string url = string.Empty, gname = string.Empty;
352
353 if (IsLocal(groupID, out url, out gname))
354 return m_LocalGroupsConnector.GetGroupRoleMembers(AgentUUI(RequestingAgentID), groupID);
355 else if (!string.IsNullOrEmpty(url))
356 {
357 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
358 string accessToken = string.Empty;
359 if (membership != null)
360 accessToken = membership.AccessToken;
361 else
362 return null;
363
364 GroupsServiceHGConnector c = GetConnector(url);
365 if (c != null)
366 {
367 return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, groupID, delegate
368 {
369 return c.GetGroupRoleMembers(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
370 });
371
372 }
373 }
374
375 return new List<GroupRoleMembersData>();
376 }
377
378 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
379 {
380 string url = string.Empty;
381 string name = string.Empty;
382 reason = string.Empty;
383
384 UUID uid = new UUID(AgentID);
385 if (IsLocal(GroupID, out url, out name))
386 {
387 if (m_UserManagement.IsLocalGridUser(uid)) // local user
388 {
389 // normal case: local group, local user
390 return m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
391 }
392 else // local group, foreign user
393 {
394 // the user is accepting the invitation, or joining, where the group resides
395 token = UUID.Random().ToString();
396 bool success = m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
397
398 if (success)
399 {
400 url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI");
401 if (url == string.Empty)
402 {
403 reason = "User doesn't have a groups server";
404 return false;
405 }
406
407 GroupsServiceHGConnector c = GetConnector(url);
408 if (c != null)
409 return c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason);
410 }
411 }
412 }
413 else if (m_UserManagement.IsLocalGridUser(uid)) // local user
414 {
415 // foreign group, local user. She's been added already by the HG service.
416 // Let's just check
417 if (m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID) != null)
418 return true;
419 }
420
421 reason = "Operation not allowed outside this group's origin world";
422 return false;
423 }
424
425
426 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
427 {
428 string url = string.Empty, name = string.Empty;
429 if (!IsLocal(GroupID, out url, out name) && url != string.Empty)
430 {
431 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
432 if (membership != null)
433 {
434 GroupsServiceHGConnector c = GetConnector(url);
435 if (c != null)
436 c.RemoveAgentFromGroup(AgentUUIForOutside(AgentID), GroupID, membership.AccessToken);
437 }
438 }
439
440 // remove from local service
441 m_LocalGroupsConnector.RemoveAgentFromGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
442 }
443
444 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
445 {
446 string url = string.Empty, gname = string.Empty;
447
448 if (IsLocal(groupID, out url, out gname))
449 return m_LocalGroupsConnector.AddAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID, groupID, roleID, AgentUUI(agentID));
450 else
451 return false;
452 }
453
454 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
455 {
456 return m_LocalGroupsConnector.GetAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); ;
457 }
458
459 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
460 {
461 m_LocalGroupsConnector.RemoveAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID);
462 }
463
464 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
465 {
466 string url = string.Empty, gname = string.Empty;
467
468 if (IsLocal(GroupID, out url, out gname))
469 m_LocalGroupsConnector.AddAgentToGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
470
471 }
472
473 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
474 {
475 string url = string.Empty, gname = string.Empty;
476
477 if (IsLocal(GroupID, out url, out gname))
478 m_LocalGroupsConnector.RemoveAgentFromGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
479 }
480
481 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
482 {
483 string url = string.Empty, gname = string.Empty;
484
485 if (IsLocal(GroupID, out url, out gname))
486 return m_LocalGroupsConnector.GetAgentGroupRoles(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
487 else
488 return new List<GroupRolesData>();
489 }
490
491 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
492 {
493 string url = string.Empty, gname = string.Empty;
494
495 if (IsLocal(GroupID, out url, out gname))
496 m_LocalGroupsConnector.SetAgentActiveGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
497 }
498
499 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
500 {
501 return m_LocalGroupsConnector.GetAgentActiveMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
502 }
503
504 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
505 {
506 string url = string.Empty, gname = string.Empty;
507
508 if (IsLocal(GroupID, out url, out gname))
509 m_LocalGroupsConnector.SetAgentActiveGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
510 }
511
512 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
513 {
514 m_LocalGroupsConnector.UpdateMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, AcceptNotices, ListInProfile);
515 }
516
517 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
518 {
519 string url = string.Empty, gname = string.Empty;
520
521 if (IsLocal(GroupID, out url, out gname))
522 return m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
523 else
524 return null;
525 }
526
527 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
528 {
529 return m_LocalGroupsConnector.GetAgentGroupMemberships(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
530 }
531
532 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
533 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
534 {
535 string url = string.Empty, gname = string.Empty;
536
537 if (IsLocal(groupID, out url, out gname))
538 {
539 if (m_LocalGroupsConnector.AddGroupNotice(AgentUUI(RequestingAgentID), groupID, noticeID, fromName, subject, message,
540 hasAttachment, attType, attName, attItemID, AgentUUI(attOwnerID)))
541 {
542 // then send the notice to every grid for which there are members in this group
543 List<GroupMembersData> members = m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), groupID);
544 List<string> urls = new List<string>();
545 foreach (GroupMembersData m in members)
546 {
547 UUID userID = UUID.Zero;
548 if (!m_UserManagement.IsLocalGridUser(m.AgentID))
549 {
550 string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI");
551 if (!urls.Contains(gURL))
552 urls.Add(gURL);
553 }
554 }
555
556 // so we have the list of urls to send the notice to
557 // this may take a long time...
558 Util.FireAndForget(delegate
559 {
560 foreach (string u in urls)
561 {
562 GroupsServiceHGConnector c = GetConnector(u);
563 if (c != null)
564 {
565 c.AddNotice(AgentUUIForOutside(RequestingAgentID), groupID, noticeID, fromName, subject, message,
566 hasAttachment, attType, attName, attItemID, AgentUUIForOutside(attOwnerID));
567 }
568 }
569 });
570
571 return true;
572 }
573
574 return false;
575 }
576 else
577 return false;
578 }
579
580 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
581 {
582 GroupNoticeInfo notice = m_LocalGroupsConnector.GetGroupNotice(AgentUUI(RequestingAgentID), noticeID);
583
584 if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
585 ImportForeigner(notice.noticeData.AttachmentOwnerID);
586
587 return notice;
588 }
589
590 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
591 {
592 return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID);
593 }
594
595 public void ResetAgentGroupChatSessions(string agentID)
596 {
597 }
598
599 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
600 {
601 return false;
602 }
603
604 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
605 {
606 return false;
607 }
608
609 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
610 {
611 }
612
613 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
614 {
615 }
616
617 #endregion
618
619 #region hypergrid groups
620
621 private string AgentUUI(string AgentIDStr)
622 {
623 UUID AgentID = UUID.Zero;
624 try
625 {
626 AgentID = new UUID(AgentIDStr);
627 }
628 catch (FormatException)
629 {
630 return AgentID.ToString();
631 }
632
633 if (m_UserManagement.IsLocalGridUser(AgentID))
634 return AgentID.ToString();
635
636 AgentCircuitData agent = null;
637 foreach (Scene scene in m_Scenes)
638 {
639 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
640 if (agent != null)
641 break;
642 }
643 if (agent == null) // oops
644 return AgentID.ToString();
645
646 return Util.ProduceUserUniversalIdentifier(agent);
647 }
648
649 private string AgentUUIForOutside(string AgentIDStr)
650 {
651 UUID AgentID = UUID.Zero;
652 try
653 {
654 AgentID = new UUID(AgentIDStr);
655 }
656 catch (FormatException)
657 {
658 return AgentID.ToString();
659 }
660
661 AgentCircuitData agent = null;
662 foreach (Scene scene in m_Scenes)
663 {
664 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
665 if (agent != null)
666 break;
667 }
668 if (agent == null) // oops
669 return AgentID.ToString();
670
671 return Util.ProduceUserUniversalIdentifier(agent);
672 }
673
674 private UUID ImportForeigner(string uID)
675 {
676 UUID userID = UUID.Zero;
677 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
678 if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp))
679 m_UserManagement.AddUser(userID, first, last, url);
680
681 return userID;
682 }
683
684 private bool IsLocal(UUID groupID, out string serviceLocation, out string name)
685 {
686 serviceLocation = string.Empty;
687 name = string.Empty;
688 ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty);
689 if (group == null)
690 {
691 //m_log.DebugFormat("[XXX]: IsLocal? group {0} not found -- no.", groupID);
692 return false;
693 }
694
695 serviceLocation = group.ServiceLocation;
696 name = group.GroupName;
697 bool isLocal = (group.ServiceLocation == string.Empty);
698 //m_log.DebugFormat("[XXX]: IsLocal? {0}", isLocal);
699 return isLocal;
700 }
701
702 private GroupsServiceHGConnector GetConnector(string url)
703 {
704 lock (m_NetworkConnectors)
705 {
706 if (m_NetworkConnectors.ContainsKey(url))
707 return m_NetworkConnectors[url];
708
709 GroupsServiceHGConnector c = new GroupsServiceHGConnector(url);
710 m_NetworkConnectors[url] = c;
711 }
712
713 return m_NetworkConnectors[url];
714 }
715 #endregion
716 }
717}
diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs
new file mode 100644
index 0000000..3584f78
--- /dev/null
+++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs
@@ -0,0 +1,444 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Text;
31using System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Server.Handlers.Base;
40using log4net;
41using OpenMetaverse;
42
43namespace OpenSim.Groups
44{
45 public class HGGroupsServiceRobustConnector : ServiceConnector
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private HGGroupsService m_GroupsService;
50 private string m_HomeURI = string.Empty;
51 private string m_ConfigName = "Groups";
52
53 // Called by Robust shell
54 public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
55 this(config, server, configName, null, null)
56 {
57 }
58
59 // Called by the sim-bound module
60 public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName, IOfflineIMService im, IUserAccountService users) :
61 base(config, server, configName)
62 {
63 if (configName != String.Empty)
64 m_ConfigName = configName;
65
66 m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName);
67
68 string homeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI",
69 new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty);
70 if (homeURI == string.Empty)
71 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName));
72
73 IConfig cnf = config.Configs[m_ConfigName];
74 if (cnf == null)
75 throw new Exception(String.Format("[Groups.RobustHGConnector]: {0} section does not exist", m_ConfigName));
76
77 if (im == null)
78 {
79 string imDll = cnf.GetString("OfflineIMService", string.Empty);
80 if (imDll == string.Empty)
81 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide OfflineIMService in section {0}", m_ConfigName));
82
83 Object[] args = new Object[] { config };
84 im = ServerUtils.LoadPlugin<IOfflineIMService>(imDll, args);
85 }
86
87 if (users == null)
88 {
89 string usersDll = cnf.GetString("UserAccountService", string.Empty);
90 if (usersDll == string.Empty)
91 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide UserAccountService in section {0}", m_ConfigName));
92
93 Object[] args = new Object[] { config };
94 users = ServerUtils.LoadPlugin<IUserAccountService>(usersDll, args);
95 }
96
97 m_GroupsService = new HGGroupsService(config, im, users, homeURI);
98
99 server.AddStreamHandler(new HGGroupsServicePostHandler(m_GroupsService));
100 }
101
102 }
103
104 public class HGGroupsServicePostHandler : BaseStreamHandler
105 {
106 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
107
108 private HGGroupsService m_GroupsService;
109
110 public HGGroupsServicePostHandler(HGGroupsService service) :
111 base("POST", "/hg-groups")
112 {
113 m_GroupsService = service;
114 }
115
116 public override byte[] Handle(string path, Stream requestData,
117 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
118 {
119 StreamReader sr = new StreamReader(requestData);
120 string body = sr.ReadToEnd();
121 sr.Close();
122 body = body.Trim();
123
124 //m_log.DebugFormat("[XXX]: query String: {0}", body);
125
126 try
127 {
128 Dictionary<string, object> request =
129 ServerUtils.ParseQueryString(body);
130
131 if (!request.ContainsKey("METHOD"))
132 return FailureResult();
133
134 string method = request["METHOD"].ToString();
135 request.Remove("METHOD");
136
137 m_log.DebugFormat("[Groups.RobustHGConnector]: {0}", method);
138 switch (method)
139 {
140 case "POSTGROUP":
141 return HandleAddGroupProxy(request);
142 case "REMOVEAGENTFROMGROUP":
143 return HandleRemoveAgentFromGroup(request);
144 case "GETGROUP":
145 return HandleGetGroup(request);
146 case "ADDNOTICE":
147 return HandleAddNotice(request);
148 case "VERIFYNOTICE":
149 return HandleVerifyNotice(request);
150 case "GETGROUPMEMBERS":
151 return HandleGetGroupMembers(request);
152 case "GETGROUPROLES":
153 return HandleGetGroupRoles(request);
154 case "GETROLEMEMBERS":
155 return HandleGetRoleMembers(request);
156
157 }
158 m_log.DebugFormat("[Groups.RobustHGConnector]: unknown method request: {0}", method);
159 }
160 catch (Exception e)
161 {
162 m_log.DebugFormat("[Groups.RobustHGConnector]: Exception {0}", e.StackTrace);
163 }
164
165 return FailureResult();
166 }
167
168 byte[] HandleAddGroupProxy(Dictionary<string, object> request)
169 {
170 Dictionary<string, object> result = new Dictionary<string, object>();
171
172 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")
173 || !request.ContainsKey("AgentID")
174 || !request.ContainsKey("AccessToken") || !request.ContainsKey("Location"))
175 NullResult(result, "Bad network data");
176
177 else
178 {
179 string RequestingAgentID = request["RequestingAgentID"].ToString();
180 string agentID = request["AgentID"].ToString();
181 UUID groupID = new UUID(request["GroupID"].ToString());
182 string accessToken = request["AccessToken"].ToString();
183 string location = request["Location"].ToString();
184 string name = string.Empty;
185 if (request.ContainsKey("Name"))
186 name = request["Name"].ToString();
187
188 string reason = string.Empty;
189 bool success = m_GroupsService.CreateGroupProxy(RequestingAgentID, agentID, accessToken, groupID, location, name, out reason);
190 result["REASON"] = reason;
191 result["RESULT"] = success.ToString();
192 }
193
194 string xmlString = ServerUtils.BuildXmlResponse(result);
195
196 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
197 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
198 }
199
200 byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
201 {
202 Dictionary<string, object> result = new Dictionary<string, object>();
203
204 if (!request.ContainsKey("AccessToken") || !request.ContainsKey("AgentID") ||
205 !request.ContainsKey("GroupID"))
206 NullResult(result, "Bad network data");
207 else
208 {
209 UUID groupID = new UUID(request["GroupID"].ToString());
210 string agentID = request["AgentID"].ToString();
211 string token = request["AccessToken"].ToString();
212 string reason = string.Empty;
213
214 m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token);
215 }
216
217 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
218 result["RESULT"] = "true";
219 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
220 }
221
222 byte[] HandleGetGroup(Dictionary<string, object> request)
223 {
224 Dictionary<string, object> result = new Dictionary<string, object>();
225
226 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AccessToken"))
227 NullResult(result, "Bad network data");
228 else
229 {
230 string RequestingAgentID = request["RequestingAgentID"].ToString();
231 string token = request["AccessToken"].ToString();
232
233 UUID groupID = UUID.Zero;
234 string groupName = string.Empty;
235
236 if (request.ContainsKey("GroupID"))
237 groupID = new UUID(request["GroupID"].ToString());
238 if (request.ContainsKey("Name"))
239 groupName = request["Name"].ToString();
240
241 ExtendedGroupRecord grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID, groupName, token);
242 if (grec == null)
243 NullResult(result, "Group not found");
244 else
245 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
246 }
247
248 string xmlString = ServerUtils.BuildXmlResponse(result);
249
250 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
251 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
252 }
253
254 byte[] HandleGetGroupMembers(Dictionary<string, object> request)
255 {
256 Dictionary<string, object> result = new Dictionary<string, object>();
257
258 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
259 NullResult(result, "Bad network data");
260 else
261 {
262 UUID groupID = new UUID(request["GroupID"].ToString());
263 string requestingAgentID = request["RequestingAgentID"].ToString();
264 string token = request["AccessToken"].ToString();
265
266 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID, token);
267 if (members == null || (members != null && members.Count == 0))
268 {
269 NullResult(result, "No members");
270 }
271 else
272 {
273 Dictionary<string, object> dict = new Dictionary<string, object>();
274 int i = 0;
275 foreach (ExtendedGroupMembersData m in members)
276 {
277 dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
278 }
279
280 result["RESULT"] = dict;
281 }
282 }
283
284 string xmlString = ServerUtils.BuildXmlResponse(result);
285
286 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
287 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
288 }
289
290 byte[] HandleGetGroupRoles(Dictionary<string, object> request)
291 {
292 Dictionary<string, object> result = new Dictionary<string, object>();
293
294 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
295 NullResult(result, "Bad network data");
296 else
297 {
298 UUID groupID = new UUID(request["GroupID"].ToString());
299 string requestingAgentID = request["RequestingAgentID"].ToString();
300 string token = request["AccessToken"].ToString();
301
302 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID, token);
303 if (roles == null || (roles != null && roles.Count == 0))
304 {
305 NullResult(result, "No members");
306 }
307 else
308 {
309 Dictionary<string, object> dict = new Dictionary<string, object>();
310 int i = 0;
311 foreach (GroupRolesData r in roles)
312 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
313
314 result["RESULT"] = dict;
315 }
316 }
317
318 string xmlString = ServerUtils.BuildXmlResponse(result);
319
320 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
321 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
322 }
323
324 byte[] HandleGetRoleMembers(Dictionary<string, object> request)
325 {
326 Dictionary<string, object> result = new Dictionary<string, object>();
327
328 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
329 NullResult(result, "Bad network data");
330 else
331 {
332 UUID groupID = new UUID(request["GroupID"].ToString());
333 string requestingAgentID = request["RequestingAgentID"].ToString();
334 string token = request["AccessToken"].ToString();
335
336 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID, token);
337 if (rmembers == null || (rmembers != null && rmembers.Count == 0))
338 {
339 NullResult(result, "No members");
340 }
341 else
342 {
343 Dictionary<string, object> dict = new Dictionary<string, object>();
344 int i = 0;
345 foreach (ExtendedGroupRoleMembersData rm in rmembers)
346 dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
347
348 result["RESULT"] = dict;
349 }
350 }
351
352 string xmlString = ServerUtils.BuildXmlResponse(result);
353
354 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
355 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
356 }
357
358 byte[] HandleAddNotice(Dictionary<string, object> request)
359 {
360 Dictionary<string, object> result = new Dictionary<string, object>();
361
362 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
363 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
364 !request.ContainsKey("HasAttachment"))
365 NullResult(result, "Bad network data");
366
367 else
368 {
369
370 bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
371 byte attType = 0;
372 string attName = string.Empty;
373 string attOwner = string.Empty;
374 UUID attItem = UUID.Zero;
375 if (request.ContainsKey("AttachmentType"))
376 attType = byte.Parse(request["AttachmentType"].ToString());
377 if (request.ContainsKey("AttachmentName"))
378 attName = request["AttachmentType"].ToString();
379 if (request.ContainsKey("AttachmentItemID"))
380 attItem = new UUID(request["AttachmentItemID"].ToString());
381 if (request.ContainsKey("AttachmentOwnerID"))
382 attOwner = request["AttachmentOwnerID"].ToString();
383
384 bool success = m_GroupsService.AddNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
385 new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
386 request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
387
388 result["RESULT"] = success.ToString();
389 }
390
391 string xmlString = ServerUtils.BuildXmlResponse(result);
392
393 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
394 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
395 }
396
397 byte[] HandleVerifyNotice(Dictionary<string, object> request)
398 {
399 Dictionary<string, object> result = new Dictionary<string, object>();
400
401 if (!request.ContainsKey("NoticeID") || !request.ContainsKey("GroupID"))
402 NullResult(result, "Bad network data");
403
404 else
405 {
406 UUID noticeID = new UUID(request["NoticeID"].ToString());
407 UUID groupID = new UUID(request["GroupID"].ToString());
408
409 bool success = m_GroupsService.VerifyNotice(noticeID, groupID);
410 //m_log.DebugFormat("[XXX]: VerifyNotice returned {0}", success);
411 result["RESULT"] = success.ToString();
412 }
413
414 string xmlString = ServerUtils.BuildXmlResponse(result);
415
416 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
417 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
418 }
419
420 //
421 //
422 //
423 //
424 //
425
426 #region Helpers
427
428 private void NullResult(Dictionary<string, object> result, string reason)
429 {
430 result["RESULT"] = "NULL";
431 result["REASON"] = reason;
432 }
433
434 private byte[] FailureResult()
435 {
436 Dictionary<string, object> result = new Dictionary<string, object>();
437 NullResult(result, "Unknown method");
438 string xmlString = ServerUtils.BuildXmlResponse(result);
439 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
440 }
441
442 #endregion
443 }
444}
diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs
new file mode 100644
index 0000000..73deb7a
--- /dev/null
+++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs
@@ -0,0 +1,118 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Groups
34{
35 public interface IGroupsServicesConnector
36 {
37 UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee,
38 bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason);
39 bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
40 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason);
41 ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName);
42 List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search);
43 List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID);
44
45 bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason);
46 bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers);
47 void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID);
48 List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID);
49 List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID);
50
51 bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason);
52 void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID);
53
54 bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID);
55 GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
56 void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
57
58 void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
59 void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
60 List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID);
61
62 void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID);
63 ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID);
64
65 void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
66 void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile);
67
68 /// <summary>
69 /// Get information about a specific group to which the user belongs.
70 /// </summary>
71 /// <param name="RequestingAgentID">The agent requesting the information.</param>
72 /// <param name="AgentID">The agent requested.</param>
73 /// <param name="GroupID">The group requested.</param>
74 /// <returns>
75 /// If the user is a member of the group then the data structure is returned. If not, then null is returned.
76 /// </returns>
77 ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID);
78
79 /// <summary>
80 /// Get information about the groups to which a user belongs.
81 /// </summary>
82 /// <param name="RequestingAgentID">The agent requesting the information.</param>
83 /// <param name="AgentID">The agent requested.</param>
84 /// <returns>
85 /// Information about the groups to which the user belongs. If the user belongs to no groups then an empty
86 /// list is returned.
87 /// </returns>
88 List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID);
89
90 bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
91 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID);
92 GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID);
93 List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID);
94
95 void ResetAgentGroupChatSessions(string agentID);
96 bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID);
97 bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID);
98 void AgentDroppedFromGroupChatSession(string agentID, UUID groupID);
99 void AgentInvitedToGroupChatSession(string agentID, UUID groupID);
100
101 }
102
103 public class GroupInviteInfo
104 {
105 public UUID GroupID = UUID.Zero;
106 public UUID RoleID = UUID.Zero;
107 public string AgentID = string.Empty;
108 public UUID InviteID = UUID.Zero;
109 }
110
111 public class GroupNoticeInfo
112 {
113 public ExtendedGroupNoticeData noticeData = new ExtendedGroupNoticeData();
114 public UUID GroupID = UUID.Zero;
115 public string Message = string.Empty;
116 }
117
118}
diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs
new file mode 100644
index 0000000..905bc91
--- /dev/null
+++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.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.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37
38using OpenMetaverse;
39using Mono.Addins;
40using log4net;
41using Nini.Config;
42
43namespace OpenSim.Groups
44{
45 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceLocalConnectorModule")]
46 public class GroupsServiceLocalConnectorModule : ISharedRegionModule, IGroupsServicesConnector
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private bool m_Enabled = false;
51 private GroupsService m_GroupsService;
52 private IUserManagement m_UserManagement;
53 private List<Scene> m_Scenes;
54 private ForeignImporter m_ForeignImporter;
55
56 #region constructors
57 public GroupsServiceLocalConnectorModule()
58 {
59 }
60
61 public GroupsServiceLocalConnectorModule(IConfigSource config, IUserManagement uman)
62 {
63 Init(config);
64 m_UserManagement = uman;
65 m_ForeignImporter = new ForeignImporter(uman);
66 }
67 #endregion
68
69 private void Init(IConfigSource config)
70 {
71 m_GroupsService = new GroupsService(config);
72 m_Scenes = new List<Scene>();
73 }
74
75 #region ISharedRegionModule
76
77 public void Initialise(IConfigSource config)
78 {
79 IConfig groupsConfig = config.Configs["Groups"];
80 if (groupsConfig == null)
81 return;
82
83 if ((groupsConfig.GetBoolean("Enabled", false) == false)
84 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
85 {
86 return;
87 }
88
89 Init(config);
90 m_Enabled = true;
91
92 m_log.DebugFormat("[Groups]: Initializing {0}", this.Name);
93 }
94
95 public string Name
96 {
97 get { return "Groups Local Service Connector"; }
98 }
99
100 public Type ReplaceableInterface
101 {
102 get { return null; }
103 }
104
105 public void AddRegion(Scene scene)
106 {
107 if (!m_Enabled)
108 return;
109
110 m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
111 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
112 m_Scenes.Add(scene);
113 }
114
115 public void RemoveRegion(Scene scene)
116 {
117 if (!m_Enabled)
118 return;
119
120 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
121 m_Scenes.Remove(scene);
122 }
123
124 public void RegionLoaded(Scene scene)
125 {
126 if (!m_Enabled)
127 return;
128
129 if (m_UserManagement == null)
130 {
131 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
132 m_ForeignImporter = new ForeignImporter(m_UserManagement);
133 }
134 }
135
136 public void PostInitialise()
137 {
138 }
139
140 public void Close()
141 {
142 }
143
144 #endregion
145
146 #region IGroupsServicesConnector
147
148 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
149 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
150 {
151 m_log.DebugFormat("[Groups]: Creating group {0}", name);
152 reason = string.Empty;
153 return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
154 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
155 }
156
157 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
158 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
159 {
160 reason = string.Empty;
161 m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
162 return true;
163 }
164
165 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
166 {
167 if (GroupID != UUID.Zero)
168 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID);
169 else if (GroupName != null)
170 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupName);
171
172 return null;
173 }
174
175 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
176 {
177 return m_GroupsService.FindGroups(RequestingAgentID, search);
178 }
179
180 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
181 {
182 List<ExtendedGroupMembersData> _members = m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
183 if (_members != null && _members.Count > 0)
184 {
185 List<GroupMembersData> members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
186 return members;
187 }
188
189 return new List<GroupMembersData>();
190 }
191
192 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
193 {
194 return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out reason);
195 }
196
197 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
198 {
199 return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
200 }
201
202 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
203 {
204 m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
205 }
206
207 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
208 {
209 return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
210 }
211
212 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
213 {
214 List<ExtendedGroupRoleMembersData> _rm = m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
215 if (_rm != null && _rm.Count > 0)
216 {
217 List<GroupRoleMembersData> rm = _rm.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
218 return rm;
219 }
220
221 return new List<GroupRoleMembersData>();
222
223 }
224
225 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
226 {
227 return m_GroupsService.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token, out reason);
228 }
229
230 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
231 {
232 m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
233 }
234
235 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
236 {
237 return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
238 }
239
240 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
241 {
242 return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); ;
243 }
244
245 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
246 {
247 m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
248 }
249
250 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
251 {
252 m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
253 }
254
255 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
256 {
257 m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
258 }
259
260 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
261 {
262 return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID);
263 }
264
265 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
266 {
267 m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
268 }
269
270 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
271 {
272 return m_GroupsService.GetAgentActiveMembership(RequestingAgentID, AgentID);
273 }
274
275 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
276 {
277 m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
278 }
279
280 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
281 {
282 m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
283 }
284
285 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
286 {
287 return m_GroupsService.GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); ;
288 }
289
290 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
291 {
292 return m_GroupsService.GetAgentGroupMemberships(RequestingAgentID, AgentID);
293 }
294
295 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
296 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
297 {
298 return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
299 hasAttachment, attType, attName, attItemID, attOwnerID);
300 }
301
302 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
303 {
304 GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
305
306 //if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
307 //{
308 // UUID userID = UUID.Zero;
309 // string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
310 // Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out userID, out url, out first, out last, out tmp);
311 // if (url != string.Empty)
312 // m_UserManagement.AddUser(userID, first, last, url);
313 //}
314
315 return notice;
316 }
317
318 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
319 {
320 return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
321 }
322
323 public void ResetAgentGroupChatSessions(string agentID)
324 {
325 }
326
327 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
328 {
329 return false;
330 }
331
332 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
333 {
334 return false;
335 }
336
337 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
338 {
339 }
340
341 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
342 {
343 }
344
345 #endregion
346 }
347}
diff --git a/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5ccd7fe
--- /dev/null
+++ b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Addons.Groups")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim.Addons.Groups")]
14[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.7.6.*")]
34
35[assembly: Addin("OpenSim.Groups", "0.1")]
36[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs
new file mode 100644
index 0000000..04328c9
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs
@@ -0,0 +1,642 @@
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;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36
37using OpenMetaverse;
38using log4net;
39
40namespace OpenSim.Groups
41{
42 public class GroupsServiceRemoteConnector
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private string m_ServerURI;
47 private object m_Lock = new object();
48
49 public GroupsServiceRemoteConnector(string url)
50 {
51 m_ServerURI = url;
52 if (!m_ServerURI.EndsWith("/"))
53 m_ServerURI += "/";
54
55 m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}", m_ServerURI);
56 }
57
58 public ExtendedGroupRecord CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
59 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
60 {
61 reason = string.Empty;
62
63 ExtendedGroupRecord rec = new ExtendedGroupRecord();
64 rec.AllowPublish = allowPublish;
65 rec.Charter = charter;
66 rec.FounderID = founderID;
67 rec.GroupName = name;
68 rec.GroupPicture = insigniaID;
69 rec.MaturePublish = maturePublish;
70 rec.MembershipFee = membershipFee;
71 rec.OpenEnrollment = openEnrollment;
72 rec.ShowInList = showInList;
73
74 Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
75 sendData["RequestingAgentID"] = RequestingAgentID;
76 sendData["OP"] = "ADD";
77 Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
78
79 if (ret == null)
80 return null;
81
82 if (ret["RESULT"].ToString() == "NULL")
83 {
84 reason = ret["REASON"].ToString();
85 return null;
86 }
87
88 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
89
90 }
91
92 public ExtendedGroupRecord UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
93 {
94 ExtendedGroupRecord rec = new ExtendedGroupRecord();
95 rec.AllowPublish = allowPublish;
96 rec.Charter = charter;
97 rec.GroupPicture = insigniaID;
98 rec.MaturePublish = maturePublish;
99 rec.GroupID = groupID;
100 rec.MembershipFee = membershipFee;
101 rec.OpenEnrollment = openEnrollment;
102 rec.ShowInList = showInList;
103
104 Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
105 sendData["RequestingAgentID"] = RequestingAgentID;
106 sendData["OP"] = "UPDATE";
107 Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
108
109 if (ret == null || (ret != null && ret["RESULT"].ToString() == "NULL"))
110 return null;
111
112 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
113 }
114
115 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
116 {
117 if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
118 return null;
119
120 Dictionary<string, object> sendData = new Dictionary<string, object>();
121 if (GroupID != UUID.Zero)
122 sendData["GroupID"] = GroupID.ToString();
123 if (GroupName != null && GroupName != string.Empty)
124 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
125
126 sendData["RequestingAgentID"] = RequestingAgentID;
127
128 Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
129
130 if (ret == null || (ret != null && ret["RESULT"].ToString() == "NULL"))
131 return null;
132
133 return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
134 }
135
136 public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
137 {
138 reason = string.Empty;
139
140 Dictionary<string, object> sendData = new Dictionary<string,object>();
141 sendData["AgentID"] = AgentID;
142 sendData["GroupID"] = GroupID.ToString();
143 sendData["RoleID"] = RoleID.ToString();
144 sendData["RequestingAgentID"] = RequestingAgentID;
145 sendData["AccessToken"] = token;
146 Dictionary<string, object> ret = MakeRequest("ADDAGENTTOGROUP", sendData);
147
148 if (ret == null)
149 return null;
150
151 if (!ret.ContainsKey("RESULT"))
152 return null;
153
154 if (ret["RESULT"].ToString() == "NULL")
155 {
156 reason = ret["REASON"].ToString();
157 return null;
158 }
159
160 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
161
162 }
163
164 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
165 {
166 Dictionary<string, object> sendData = new Dictionary<string, object>();
167 sendData["AgentID"] = AgentID;
168 sendData["GroupID"] = GroupID.ToString();
169 sendData["RequestingAgentID"] = RequestingAgentID;
170 MakeRequest("REMOVEAGENTFROMGROUP", sendData);
171 }
172
173 public ExtendedGroupMembershipData GetMembership(string RequestingAgentID, string AgentID, UUID GroupID)
174 {
175 Dictionary<string, object> sendData = new Dictionary<string, object>();
176 sendData["AgentID"] = AgentID;
177 if (GroupID != UUID.Zero)
178 sendData["GroupID"] = GroupID.ToString();
179 sendData["RequestingAgentID"] = RequestingAgentID;
180 Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
181
182 if (ret == null)
183 return null;
184
185 if (!ret.ContainsKey("RESULT"))
186 return null;
187
188 if (ret["RESULT"].ToString() == "NULL")
189 return null;
190
191 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
192 }
193
194 public List<GroupMembershipData> GetMemberships(string RequestingAgentID, string AgentID)
195 {
196 List<GroupMembershipData> memberships = new List<GroupMembershipData>();
197
198 Dictionary<string, object> sendData = new Dictionary<string, object>();
199 sendData["AgentID"] = AgentID;
200 sendData["ALL"] = "true";
201 sendData["RequestingAgentID"] = RequestingAgentID;
202 Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
203
204 if (ret == null)
205 return memberships;
206
207 if (!ret.ContainsKey("RESULT"))
208 return memberships;
209
210 if (ret["RESULT"].ToString() == "NULL")
211 return memberships;
212
213 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
214 {
215 GroupMembershipData m = GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)v);
216 memberships.Add(m);
217 }
218
219 return memberships;
220 }
221
222 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
223 {
224 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
225
226 Dictionary<string, object> sendData = new Dictionary<string, object>();
227 sendData["GroupID"] = GroupID.ToString();
228 sendData["RequestingAgentID"] = RequestingAgentID;
229 Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
230
231 if (ret == null)
232 return members;
233
234 if (!ret.ContainsKey("RESULT"))
235 return members;
236
237 if (ret["RESULT"].ToString() == "NULL")
238 return members;
239 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
240 {
241 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
242 members.Add(m);
243 }
244
245 return members;
246 }
247
248 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
249 {
250 reason = string.Empty;
251
252 Dictionary<string, object> sendData = new Dictionary<string, object>();
253 sendData["GroupID"] = groupID.ToString();
254 sendData["RoleID"] = roleID.ToString();
255 sendData["Name"] = GroupsDataUtils.Sanitize(name);
256 sendData["Description"] = GroupsDataUtils.Sanitize(description);
257 sendData["Title"] = GroupsDataUtils.Sanitize(title);
258 sendData["Powers"] = powers.ToString();
259 sendData["RequestingAgentID"] = RequestingAgentID;
260 sendData["OP"] = "ADD";
261 Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
262
263 if (ret == null)
264 return false;
265
266 if (!ret.ContainsKey("RESULT"))
267 return false;
268
269 if (ret["RESULT"].ToString().ToLower() != "true")
270 {
271 reason = ret["REASON"].ToString();
272 return false;
273 }
274
275 return true;
276 }
277
278 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
279 {
280 Dictionary<string, object> sendData = new Dictionary<string, object>();
281 sendData["GroupID"] = groupID.ToString();
282 sendData["RoleID"] = roleID.ToString();
283 sendData["Name"] = GroupsDataUtils.Sanitize(name);
284 sendData["Description"] = GroupsDataUtils.Sanitize(description);
285 sendData["Title"] = GroupsDataUtils.Sanitize(title);
286 sendData["Powers"] = powers.ToString();
287 sendData["RequestingAgentID"] = RequestingAgentID;
288 sendData["OP"] = "UPDATE";
289 Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
290
291 if (ret == null)
292 return false;
293
294 if (!ret.ContainsKey("RESULT"))
295 return false;
296
297 if (ret["RESULT"].ToString().ToLower() != "true")
298 return false;
299
300 return true;
301 }
302
303 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
304 {
305 Dictionary<string, object> sendData = new Dictionary<string, object>();
306 sendData["GroupID"] = groupID.ToString();
307 sendData["RoleID"] = roleID.ToString();
308 sendData["RequestingAgentID"] = RequestingAgentID;
309 MakeRequest("REMOVEROLE", sendData);
310 }
311
312 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
313 {
314 List<GroupRolesData> roles = new List<GroupRolesData>();
315
316 Dictionary<string, object> sendData = new Dictionary<string, object>();
317 sendData["GroupID"] = GroupID.ToString();
318 sendData["RequestingAgentID"] = RequestingAgentID;
319 Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
320
321 if (ret == null)
322 return roles;
323
324 if (!ret.ContainsKey("RESULT"))
325 return roles;
326
327 if (ret["RESULT"].ToString() == "NULL")
328 return roles;
329 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
330 {
331 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
332 roles.Add(m);
333 }
334
335 return roles;
336 }
337
338 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
339 {
340 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
341
342 Dictionary<string, object> sendData = new Dictionary<string, object>();
343 sendData["GroupID"] = GroupID.ToString();
344 sendData["RequestingAgentID"] = RequestingAgentID;
345 Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
346
347 if (ret == null)
348 return rmembers;
349
350 if (!ret.ContainsKey("RESULT"))
351 return rmembers;
352
353 if (ret["RESULT"].ToString() == "NULL")
354 return rmembers;
355
356 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
357 {
358 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
359 rmembers.Add(m);
360 }
361
362 return rmembers;
363 }
364
365 public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
366 {
367 Dictionary<string, object> sendData = new Dictionary<string, object>();
368 sendData["AgentID"] = AgentID.ToString();
369 sendData["GroupID"] = GroupID.ToString();
370 sendData["RoleID"] = RoleID.ToString();
371 sendData["RequestingAgentID"] = RequestingAgentID;
372 sendData["OP"] = "ADD";
373
374 Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
375
376 if (ret == null)
377 return false;
378
379 if (!ret.ContainsKey("RESULT"))
380 return false;
381
382 if (ret["RESULT"].ToString().ToLower() != "true")
383 return false;
384
385 return true;
386 }
387
388 public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
389 {
390 Dictionary<string, object> sendData = new Dictionary<string, object>();
391 sendData["AgentID"] = AgentID.ToString();
392 sendData["GroupID"] = GroupID.ToString();
393 sendData["RoleID"] = RoleID.ToString();
394 sendData["RequestingAgentID"] = RequestingAgentID;
395 sendData["OP"] = "DELETE";
396
397 Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
398
399 if (ret == null)
400 return false;
401
402 if (!ret.ContainsKey("RESULT"))
403 return false;
404
405 if (ret["RESULT"].ToString().ToLower() != "true")
406 return false;
407
408 return true;
409 }
410
411 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
412 {
413 List<GroupRolesData> roles = new List<GroupRolesData>();
414
415 Dictionary<string, object> sendData = new Dictionary<string, object>();
416 sendData["AgentID"] = AgentID.ToString();
417 sendData["GroupID"] = GroupID.ToString();
418 sendData["RequestingAgentID"] = RequestingAgentID;
419 Dictionary<string, object> ret = MakeRequest("GETAGENTROLES", sendData);
420
421 if (ret == null)
422 return roles;
423
424 if (!ret.ContainsKey("RESULT"))
425 return roles;
426
427 if (ret["RESULT"].ToString() == "NULL")
428 return roles;
429
430 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
431 {
432 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
433 roles.Add(m);
434 }
435
436 return roles;
437 }
438
439 public GroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
440 {
441 Dictionary<string, object> sendData = new Dictionary<string, object>();
442 sendData["AgentID"] = AgentID.ToString();
443 sendData["GroupID"] = GroupID.ToString();
444 sendData["RequestingAgentID"] = RequestingAgentID;
445 sendData["OP"] = "GROUP";
446
447 Dictionary<string, object> ret = MakeRequest("SETACTIVE", sendData);
448
449 if (ret == null)
450 return null;
451
452 if (!ret.ContainsKey("RESULT"))
453 return null;
454
455 if (ret["RESULT"].ToString() == "NULL")
456 return null;
457
458 return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
459 }
460
461 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
462 {
463 Dictionary<string, object> sendData = new Dictionary<string, object>();
464 sendData["AgentID"] = AgentID.ToString();
465 sendData["GroupID"] = GroupID.ToString();
466 sendData["RoleID"] = RoleID.ToString();
467 sendData["RequestingAgentID"] = RequestingAgentID;
468 sendData["OP"] = "ROLE";
469
470 MakeRequest("SETACTIVE", sendData);
471 }
472
473 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
474 {
475 Dictionary<string, object> sendData = new Dictionary<string, object>();
476 sendData["AgentID"] = AgentID.ToString();
477 sendData["GroupID"] = GroupID.ToString();
478 sendData["AcceptNotices"] = AcceptNotices.ToString();
479 sendData["ListInProfile"] = ListInProfile.ToString();
480 sendData["RequestingAgentID"] = RequestingAgentID;
481 MakeRequest("UPDATEMEMBERSHIP", sendData);
482 }
483
484 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
485 {
486 Dictionary<string, object> sendData = new Dictionary<string, object>();
487 sendData["InviteID"] = inviteID.ToString();
488 sendData["GroupID"] = groupID.ToString();
489 sendData["RoleID"] = roleID.ToString();
490 sendData["AgentID"] = agentID.ToString();
491 sendData["RequestingAgentID"] = RequestingAgentID;
492 sendData["OP"] = "ADD";
493
494 Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
495
496 if (ret == null)
497 return false;
498
499 if (!ret.ContainsKey("RESULT"))
500 return false;
501
502 if (ret["RESULT"].ToString().ToLower() != "true") // it may return "NULL"
503 return false;
504
505 return true;
506 }
507
508 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
509 {
510 Dictionary<string, object> sendData = new Dictionary<string, object>();
511 sendData["InviteID"] = inviteID.ToString();
512 sendData["RequestingAgentID"] = RequestingAgentID;
513 sendData["OP"] = "GET";
514
515 Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
516
517 if (ret == null)
518 return null;
519
520 if (!ret.ContainsKey("RESULT"))
521 return null;
522
523 if (ret["RESULT"].ToString() == "NULL")
524 return null;
525
526 return GroupsDataUtils.GroupInviteInfo((Dictionary<string, object>)ret["RESULT"]);
527 }
528
529 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
530 {
531 Dictionary<string, object> sendData = new Dictionary<string, object>();
532 sendData["InviteID"] = inviteID.ToString();
533 sendData["RequestingAgentID"] = RequestingAgentID;
534 sendData["OP"] = "DELETE";
535
536 MakeRequest("INVITE", sendData);
537 }
538
539 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
540 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
541 {
542 Dictionary<string, object> sendData = new Dictionary<string, object>();
543 sendData["GroupID"] = groupID.ToString();
544 sendData["NoticeID"] = noticeID.ToString();
545 sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
546 sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
547 sendData["Message"] = GroupsDataUtils.Sanitize(message);
548 sendData["HasAttachment"] = hasAttachment.ToString();
549 if (hasAttachment)
550 {
551 sendData["AttachmentType"] = attType.ToString();
552 sendData["AttachmentName"] = attName.ToString();
553 sendData["AttachmentItemID"] = attItemID.ToString();
554 sendData["AttachmentOwnerID"] = attOwnerID;
555 }
556 sendData["RequestingAgentID"] = RequestingAgentID;
557
558 Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
559
560 if (ret == null)
561 return false;
562
563 if (!ret.ContainsKey("RESULT"))
564 return false;
565
566 if (ret["RESULT"].ToString().ToLower() != "true")
567 return false;
568
569 return true;
570 }
571
572 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
573 {
574 Dictionary<string, object> sendData = new Dictionary<string, object>();
575 sendData["NoticeID"] = noticeID.ToString();
576 sendData["RequestingAgentID"] = RequestingAgentID;
577
578 Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
579
580 if (ret == null)
581 return null;
582
583 if (!ret.ContainsKey("RESULT"))
584 return null;
585
586 if (ret["RESULT"].ToString() == "NULL")
587 return null;
588
589 return GroupsDataUtils.GroupNoticeInfo((Dictionary<string, object>)ret["RESULT"]);
590 }
591
592 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
593 {
594 List<ExtendedGroupNoticeData> notices = new List<ExtendedGroupNoticeData>();
595
596 Dictionary<string, object> sendData = new Dictionary<string, object>();
597 sendData["GroupID"] = GroupID.ToString();
598 sendData["RequestingAgentID"] = RequestingAgentID;
599 Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
600
601 if (ret == null)
602 return notices;
603
604 if (!ret.ContainsKey("RESULT"))
605 return notices;
606
607 if (ret["RESULT"].ToString() == "NULL")
608 return notices;
609
610 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
611 {
612 ExtendedGroupNoticeData m = GroupsDataUtils.GroupNoticeData((Dictionary<string, object>)v);
613 notices.Add(m);
614 }
615
616 return notices;
617 }
618
619 #region Make Request
620
621 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
622 {
623 sendData["METHOD"] = method;
624
625 string reply = string.Empty;
626 lock (m_Lock)
627 reply = SynchronousRestFormsRequester.MakeRequest("POST",
628 m_ServerURI + "groups",
629 ServerUtils.BuildQueryString(sendData));
630
631 if (reply == string.Empty)
632 return null;
633
634 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
635 reply);
636
637 return replyData;
638 }
639 #endregion
640
641 }
642}
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs
new file mode 100644
index 0000000..f1cf66c
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs
@@ -0,0 +1,434 @@
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.Threading;
33using System.Text;
34
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Server.Base;
39
40using OpenMetaverse;
41using Mono.Addins;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Groups
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceRemoteConnectorModule")]
48 public class GroupsServiceRemoteConnectorModule : ISharedRegionModule, IGroupsServicesConnector
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private bool m_Enabled = false;
53 private GroupsServiceRemoteConnector m_GroupsService;
54 private IUserManagement m_UserManagement;
55 private List<Scene> m_Scenes;
56
57 private RemoteConnectorCacheWrapper m_CacheWrapper;
58
59 #region constructors
60 public GroupsServiceRemoteConnectorModule()
61 {
62 }
63
64 public GroupsServiceRemoteConnectorModule(IConfigSource config, IUserManagement uman)
65 {
66 Init(config);
67 m_UserManagement = uman;
68 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
69
70 }
71 #endregion
72
73 private void Init(IConfigSource config)
74 {
75 IConfig groupsConfig = config.Configs["Groups"];
76 string url = groupsConfig.GetString("GroupsServerURI", string.Empty);
77 if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
78 throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url));
79
80 m_GroupsService = new GroupsServiceRemoteConnector(url);
81 m_Scenes = new List<Scene>();
82
83 }
84
85 #region ISharedRegionModule
86
87 public void Initialise(IConfigSource config)
88 {
89 IConfig groupsConfig = config.Configs["Groups"];
90 if (groupsConfig == null)
91 return;
92
93 if ((groupsConfig.GetBoolean("Enabled", false) == false)
94 || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
95 {
96 return;
97 }
98
99 Init(config);
100
101 m_Enabled = true;
102 m_log.DebugFormat("[Groups.RemoteConnector]: Initializing {0}", this.Name);
103 }
104
105 public string Name
106 {
107 get { return "Groups Remote Service Connector"; }
108 }
109
110 public Type ReplaceableInterface
111 {
112 get { return null; }
113 }
114
115 public void AddRegion(Scene scene)
116 {
117 if (!m_Enabled)
118 return;
119
120 m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
121 scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
122 m_Scenes.Add(scene);
123 }
124
125 public void RemoveRegion(Scene scene)
126 {
127 if (!m_Enabled)
128 return;
129
130 scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
131 m_Scenes.Remove(scene);
132 }
133
134 public void RegionLoaded(Scene scene)
135 {
136 if (!m_Enabled)
137 return;
138
139 if (m_UserManagement == null)
140 {
141 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
142 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
143 }
144 }
145
146 public void PostInitialise()
147 {
148 }
149
150 public void Close()
151 {
152 }
153
154 #endregion
155
156 #region IGroupsServicesConnector
157
158 public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
159 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
160 {
161 m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
162 string r = string.Empty;
163
164 UUID groupID = m_CacheWrapper.CreateGroup(RequestingAgentID, delegate
165 {
166 return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
167 membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out r);
168 });
169
170 reason = r;
171 return groupID;
172 }
173
174 public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
175 bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
176 {
177 string r = string.Empty;
178
179 bool success = m_CacheWrapper.UpdateGroup(groupID, delegate
180 {
181 return m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
182 });
183
184 reason = r;
185 return success;
186 }
187
188 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
189 {
190 if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
191 return null;
192
193 return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate
194 {
195 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
196 });
197 }
198
199 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
200 {
201 // TODO!
202 return new List<DirGroupsReplyData>();
203 }
204
205 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
206 {
207 string agentFullID = AgentID;
208 m_log.DebugFormat("[Groups.RemoteConnector]: Add agent {0} to group {1}", agentFullID, GroupID);
209 string r = string.Empty;
210
211 bool success = m_CacheWrapper.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, delegate
212 {
213 return m_GroupsService.AddAgentToGroup(RequestingAgentID, agentFullID, GroupID, RoleID, token, out r);
214 });
215
216 reason = r;
217 return success;
218 }
219
220 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
221 {
222 m_CacheWrapper.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID, delegate
223 {
224 m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
225 });
226
227 }
228
229 public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
230 {
231 m_CacheWrapper.SetAgentActiveGroup(AgentID, delegate
232 {
233 return m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
234 });
235 }
236
237 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
238 {
239 return m_CacheWrapper.GetAgentActiveMembership(AgentID, delegate
240 {
241 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, UUID.Zero);
242 });
243 }
244
245 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
246 {
247 return m_CacheWrapper.GetAgentGroupMembership(AgentID, GroupID, delegate
248 {
249 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, GroupID);
250 });
251 }
252
253 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
254 {
255 return m_CacheWrapper.GetAgentGroupMemberships(AgentID, delegate
256 {
257 return m_GroupsService.GetMemberships(RequestingAgentID, AgentID);
258 });
259 }
260
261
262 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
263 {
264 return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
265 {
266 return m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
267 });
268 }
269
270 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
271 {
272 string r = string.Empty;
273 bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate
274 {
275 return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r);
276 });
277
278 reason = r;
279 return success;
280 }
281
282 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
283 {
284 return m_CacheWrapper.UpdateGroupRole(groupID, roleID, name, description, title, powers, delegate
285 {
286 return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
287 });
288 }
289
290 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
291 {
292 m_CacheWrapper.RemoveGroupRole(RequestingAgentID, groupID, roleID, delegate
293 {
294 m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
295 });
296 }
297
298 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
299 {
300 return m_CacheWrapper.GetGroupRoles(RequestingAgentID, GroupID, delegate
301 {
302 return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
303 });
304 }
305
306 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
307 {
308 return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, GroupID, delegate
309 {
310 return m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
311 });
312 }
313
314 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
315 {
316 m_CacheWrapper.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
317 {
318 return m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
319 });
320 }
321
322 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
323 {
324 m_CacheWrapper.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
325 {
326 return m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
327 });
328 }
329
330 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
331 {
332 return m_CacheWrapper.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID, delegate
333 {
334 return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); ;
335 });
336 }
337
338 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
339 {
340 m_CacheWrapper.SetAgentActiveGroupRole(AgentID, GroupID, delegate
341 {
342 m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
343 });
344 }
345
346 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
347 {
348 m_CacheWrapper.UpdateMembership(AgentID, GroupID, AcceptNotices, ListInProfile, delegate
349 {
350 m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
351 });
352 }
353
354 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
355 {
356 return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
357 }
358
359 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
360 {
361 return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID);
362 }
363
364 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
365 {
366 m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
367 }
368
369 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
370 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
371 {
372 GroupNoticeInfo notice = new GroupNoticeInfo();
373 notice.GroupID = groupID;
374 notice.Message = message;
375 notice.noticeData = new ExtendedGroupNoticeData();
376 notice.noticeData.AttachmentItemID = attItemID;
377 notice.noticeData.AttachmentName = attName;
378 notice.noticeData.AttachmentOwnerID = attOwnerID.ToString();
379 notice.noticeData.AttachmentType = attType;
380 notice.noticeData.FromName = fromName;
381 notice.noticeData.HasAttachment = hasAttachment;
382 notice.noticeData.NoticeID = noticeID;
383 notice.noticeData.Subject = subject;
384 notice.noticeData.Timestamp = (uint)Util.UnixTimeSinceEpoch();
385
386 return m_CacheWrapper.AddGroupNotice(groupID, noticeID, notice, delegate
387 {
388 return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
389 hasAttachment, attType, attName, attItemID, attOwnerID);
390 });
391 }
392
393 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
394 {
395 return m_CacheWrapper.GetGroupNotice(noticeID, delegate
396 {
397 return m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
398 });
399 }
400
401 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
402 {
403 return m_CacheWrapper.GetGroupNotices(GroupID, delegate
404 {
405 return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
406 });
407 }
408
409 public void ResetAgentGroupChatSessions(string agentID)
410 {
411 }
412
413 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
414 {
415 return false;
416 }
417
418 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
419 {
420 return false;
421 }
422
423 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
424 {
425 }
426
427 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
428 {
429 }
430
431 #endregion
432 }
433
434}
diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
new file mode 100644
index 0000000..f991d01
--- /dev/null
+++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs
@@ -0,0 +1,760 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Text;
31using System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Server.Handlers.Base;
40using log4net;
41using OpenMetaverse;
42
43namespace OpenSim.Groups
44{
45 public class GroupsServiceRobustConnector : ServiceConnector
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private GroupsService m_GroupsService;
50 private string m_ConfigName = "Groups";
51
52 public GroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
53 base(config, server, configName)
54 {
55 if (configName != String.Empty)
56 m_ConfigName = configName;
57
58 m_log.DebugFormat("[Groups.RobustConnector]: Starting with config name {0}", m_ConfigName);
59
60 m_GroupsService = new GroupsService(config);
61
62 server.AddStreamHandler(new GroupsServicePostHandler(m_GroupsService));
63 }
64 }
65
66 public class GroupsServicePostHandler : BaseStreamHandler
67 {
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
70 private GroupsService m_GroupsService;
71
72 public GroupsServicePostHandler(GroupsService service) :
73 base("POST", "/groups")
74 {
75 m_GroupsService = service;
76 }
77
78 public override byte[] Handle(string path, Stream requestData,
79 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
80 {
81 StreamReader sr = new StreamReader(requestData);
82 string body = sr.ReadToEnd();
83 sr.Close();
84 body = body.Trim();
85
86 //m_log.DebugFormat("[XXX]: query String: {0}", body);
87
88 try
89 {
90 Dictionary<string, object> request =
91 ServerUtils.ParseQueryString(body);
92
93 if (!request.ContainsKey("METHOD"))
94 return FailureResult();
95
96 string method = request["METHOD"].ToString();
97 request.Remove("METHOD");
98
99 m_log.DebugFormat("[Groups.Handler]: {0}", method);
100 switch (method)
101 {
102 case "PUTGROUP":
103 return HandleAddOrUpdateGroup(request);
104 case "GETGROUP":
105 return HandleGetGroup(request);
106 case "ADDAGENTTOGROUP":
107 return HandleAddAgentToGroup(request);
108 case "REMOVEAGENTFROMGROUP":
109 return HandleRemoveAgentFromGroup(request);
110 case "GETMEMBERSHIP":
111 return HandleGetMembership(request);
112 case "GETGROUPMEMBERS":
113 return HandleGetGroupMembers(request);
114 case "PUTROLE":
115 return HandlePutRole(request);
116 case "REMOVEROLE":
117 return HandleRemoveRole(request);
118 case "GETGROUPROLES":
119 return HandleGetGroupRoles(request);
120 case "GETROLEMEMBERS":
121 return HandleGetRoleMembers(request);
122 case "AGENTROLE":
123 return HandleAgentRole(request);
124 case "GETAGENTROLES":
125 return HandleGetAgentRoles(request);
126 case "SETACTIVE":
127 return HandleSetActive(request);
128 case "UPDATEMEMBERSHIP":
129 return HandleUpdateMembership(request);
130 case "INVITE":
131 return HandleInvite(request);
132 case "ADDNOTICE":
133 return HandleAddNotice(request);
134 case "GETNOTICES":
135 return HandleGetNotices(request);
136 }
137 m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method);
138 }
139 catch (Exception e)
140 {
141 m_log.DebugFormat("[GROUPS HANDLER]: Exception {0}", e.StackTrace);
142 }
143
144 return FailureResult();
145 }
146
147 byte[] HandleAddOrUpdateGroup(Dictionary<string, object> request)
148 {
149 Dictionary<string, object> result = new Dictionary<string, object>();
150
151 ExtendedGroupRecord grec = GroupsDataUtils.GroupRecord(request);
152 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("OP"))
153 NullResult(result, "Bad network data");
154
155 else
156 {
157 string RequestingAgentID = request["RequestingAgentID"].ToString();
158 string reason = string.Empty;
159 string op = request["OP"].ToString();
160 if (op == "ADD")
161 {
162 grec.GroupID = m_GroupsService.CreateGroup(RequestingAgentID, grec.GroupName, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
163 grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish, grec.FounderID, out reason);
164
165 }
166 else if (op == "UPDATE")
167 {
168 m_GroupsService.UpdateGroup(RequestingAgentID, grec.GroupID, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
169 grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish);
170
171 }
172
173 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
174 if (grec == null)
175 NullResult(result, "Internal Error");
176 else
177 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
178 }
179
180 string xmlString = ServerUtils.BuildXmlResponse(result);
181
182 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
183 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
184 }
185
186 byte[] HandleGetGroup(Dictionary<string, object> request)
187 {
188 Dictionary<string, object> result = new Dictionary<string, object>();
189
190 if (!request.ContainsKey("RequestingAgentID"))
191 NullResult(result, "Bad network data");
192 else
193 {
194 string RequestingAgentID = request["RequestingAgentID"].ToString();
195 ExtendedGroupRecord grec = null;
196 if (request.ContainsKey("GroupID"))
197 {
198 UUID groupID = new UUID(request["GroupID"].ToString());
199 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID);
200 }
201 else if (request.ContainsKey("Name"))
202 {
203 string name = request["Name"].ToString();
204 grec = m_GroupsService.GetGroupRecord(RequestingAgentID, name);
205 }
206
207 if (grec == null)
208 NullResult(result, "Group not found");
209 else
210 result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
211 }
212
213 string xmlString = ServerUtils.BuildXmlResponse(result);
214
215 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
216 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
217 }
218
219 byte[] HandleAddAgentToGroup(Dictionary<string, object> request)
220 {
221 Dictionary<string, object> result = new Dictionary<string, object>();
222
223 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") ||
224 !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
225 NullResult(result, "Bad network data");
226 else
227 {
228 UUID groupID = new UUID(request["GroupID"].ToString());
229 UUID roleID = new UUID(request["RoleID"].ToString());
230 string agentID = request["AgentID"].ToString();
231 string requestingAgentID = request["RequestingAgentID"].ToString();
232 string token = string.Empty;
233 string reason = string.Empty;
234
235 if (request.ContainsKey("AccessToken"))
236 token = request["AccessToken"].ToString();
237
238 if (!m_GroupsService.AddAgentToGroup(requestingAgentID, agentID, groupID, roleID, token, out reason))
239 NullResult(result, reason);
240 else
241 {
242 GroupMembershipData membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
243 if (membership == null)
244 NullResult(result, "Internal error");
245 else
246 result["RESULT"] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)membership);
247 }
248 }
249
250 string xmlString = ServerUtils.BuildXmlResponse(result);
251
252 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
253 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
254 }
255
256 byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
257 {
258 Dictionary<string, object> result = new Dictionary<string, object>();
259
260 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID"))
261 NullResult(result, "Bad network data");
262 else
263 {
264 UUID groupID = new UUID(request["GroupID"].ToString());
265 string agentID = request["AgentID"].ToString();
266 string requestingAgentID = request["RequestingAgentID"].ToString();
267 string reason = string.Empty;
268
269 m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID);
270 }
271
272 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
273 result["RESULT"] = "true";
274 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
275 }
276
277 byte[] HandleGetMembership(Dictionary<string, object> request)
278 {
279 Dictionary<string, object> result = new Dictionary<string, object>();
280
281 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID"))
282 NullResult(result, "Bad network data");
283 else
284 {
285 string agentID = request["AgentID"].ToString();
286 UUID groupID = UUID.Zero;
287 if (request.ContainsKey("GroupID"))
288 groupID = new UUID(request["GroupID"].ToString());
289 string requestingAgentID = request["RequestingAgentID"].ToString();
290 bool all = request.ContainsKey("ALL");
291
292 if (!all)
293 {
294 ExtendedGroupMembershipData membership = null;
295 if (groupID == UUID.Zero)
296 {
297 membership = m_GroupsService.GetAgentActiveMembership(requestingAgentID, agentID);
298 }
299 else
300 {
301 membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
302 }
303
304 if (membership == null)
305 NullResult(result, "No such membership");
306 else
307 result["RESULT"] = GroupsDataUtils.GroupMembershipData(membership);
308 }
309 else
310 {
311 List<GroupMembershipData> memberships = m_GroupsService.GetAgentGroupMemberships(requestingAgentID, agentID);
312 if (memberships == null || (memberships != null && memberships.Count == 0))
313 {
314 NullResult(result, "No memberships");
315 }
316 else
317 {
318 Dictionary<string, object> dict = new Dictionary<string, object>();
319 int i = 0;
320 foreach (GroupMembershipData m in memberships)
321 dict["m-" + i++] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)m);
322
323 result["RESULT"] = dict;
324 }
325 }
326 }
327
328 string xmlString = ServerUtils.BuildXmlResponse(result);
329
330 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
331 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
332 }
333
334 byte[] HandleGetGroupMembers(Dictionary<string, object> request)
335 {
336 Dictionary<string, object> result = new Dictionary<string, object>();
337
338 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
339 NullResult(result, "Bad network data");
340 else
341 {
342 UUID groupID = new UUID(request["GroupID"].ToString());
343 string requestingAgentID = request["RequestingAgentID"].ToString();
344
345 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID);
346 if (members == null || (members != null && members.Count == 0))
347 {
348 NullResult(result, "No members");
349 }
350 else
351 {
352 Dictionary<string, object> dict = new Dictionary<string, object>();
353 int i = 0;
354 foreach (ExtendedGroupMembersData m in members)
355 {
356 dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
357 }
358
359 result["RESULT"] = dict;
360 }
361 }
362
363 string xmlString = ServerUtils.BuildXmlResponse(result);
364
365 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
366 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
367 }
368
369 byte[] HandlePutRole(Dictionary<string, object> request)
370 {
371 Dictionary<string, object> result = new Dictionary<string, object>();
372
373 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
374 !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") ||
375 !request.ContainsKey("Powers") || !request.ContainsKey("OP"))
376 NullResult(result, "Bad network data");
377
378 else
379 {
380 string op = request["OP"].ToString();
381 string reason = string.Empty;
382
383 bool success = false;
384 if (op == "ADD")
385 success = m_GroupsService.AddGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
386 new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
387 request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()), out reason);
388
389 else if (op == "UPDATE")
390 success = m_GroupsService.UpdateGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
391 new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
392 request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()));
393
394 result["RESULT"] = success.ToString();
395 }
396
397 string xmlString = ServerUtils.BuildXmlResponse(result);
398
399 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
400 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
401 }
402
403 byte[] HandleRemoveRole(Dictionary<string, object> request)
404 {
405 Dictionary<string, object> result = new Dictionary<string, object>();
406
407 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
408 NullResult(result, "Bad network data");
409
410 else
411 {
412 m_GroupsService.RemoveGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
413 new UUID(request["RoleID"].ToString()));
414 result["RESULT"] = "true";
415 }
416
417 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
418 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
419 }
420
421 byte[] HandleGetGroupRoles(Dictionary<string, object> request)
422 {
423 Dictionary<string, object> result = new Dictionary<string, object>();
424
425 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
426 NullResult(result, "Bad network data");
427 else
428 {
429 UUID groupID = new UUID(request["GroupID"].ToString());
430 string requestingAgentID = request["RequestingAgentID"].ToString();
431
432 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID);
433 if (roles == null || (roles != null && roles.Count == 0))
434 {
435 NullResult(result, "No members");
436 }
437 else
438 {
439 Dictionary<string, object> dict = new Dictionary<string, object>();
440 int i = 0;
441 foreach (GroupRolesData r in roles)
442 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
443
444 result["RESULT"] = dict;
445 }
446 }
447
448 string xmlString = ServerUtils.BuildXmlResponse(result);
449
450 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
451 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
452 }
453
454 byte[] HandleGetRoleMembers(Dictionary<string, object> request)
455 {
456 Dictionary<string, object> result = new Dictionary<string, object>();
457
458 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
459 NullResult(result, "Bad network data");
460 else
461 {
462 UUID groupID = new UUID(request["GroupID"].ToString());
463 string requestingAgentID = request["RequestingAgentID"].ToString();
464
465 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID);
466 if (rmembers == null || (rmembers != null && rmembers.Count == 0))
467 {
468 NullResult(result, "No members");
469 }
470 else
471 {
472 Dictionary<string, object> dict = new Dictionary<string, object>();
473 int i = 0;
474 foreach (ExtendedGroupRoleMembersData rm in rmembers)
475 dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
476
477 result["RESULT"] = dict;
478 }
479 }
480
481 string xmlString = ServerUtils.BuildXmlResponse(result);
482
483 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
484 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
485 }
486
487 byte[] HandleAgentRole(Dictionary<string, object> request)
488 {
489 Dictionary<string, object> result = new Dictionary<string, object>();
490
491 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
492 !request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
493 NullResult(result, "Bad network data");
494
495 else
496 {
497 string op = request["OP"].ToString();
498 string reason = string.Empty;
499
500 bool success = false;
501 if (op == "ADD")
502 success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
503 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
504
505 else if (op == "DELETE")
506 success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
507 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
508
509 result["RESULT"] = success.ToString();
510 }
511
512 string xmlString = ServerUtils.BuildXmlResponse(result);
513
514 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
515 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
516 }
517
518 byte[] HandleGetAgentRoles(Dictionary<string, object> request)
519 {
520 Dictionary<string, object> result = new Dictionary<string, object>();
521
522 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AgentID"))
523 NullResult(result, "Bad network data");
524 else
525 {
526 UUID groupID = new UUID(request["GroupID"].ToString());
527 string agentID = request["AgentID"].ToString();
528 string requestingAgentID = request["RequestingAgentID"].ToString();
529
530 List<GroupRolesData> roles = m_GroupsService.GetAgentGroupRoles(requestingAgentID, agentID, groupID);
531 if (roles == null || (roles != null && roles.Count == 0))
532 {
533 NullResult(result, "No members");
534 }
535 else
536 {
537 Dictionary<string, object> dict = new Dictionary<string, object>();
538 int i = 0;
539 foreach (GroupRolesData r in roles)
540 dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
541
542 result["RESULT"] = dict;
543 }
544 }
545
546 string xmlString = ServerUtils.BuildXmlResponse(result);
547
548 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
549 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
550 }
551
552 byte[] HandleSetActive(Dictionary<string, object> request)
553 {
554 Dictionary<string, object> result = new Dictionary<string, object>();
555
556 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") ||
557 !request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
558 {
559 NullResult(result, "Bad network data");
560 string xmlString = ServerUtils.BuildXmlResponse(result);
561 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
562 }
563 else
564 {
565 string op = request["OP"].ToString();
566 string reason = string.Empty;
567
568 if (op == "GROUP")
569 {
570 ExtendedGroupMembershipData group = m_GroupsService.SetAgentActiveGroup(request["RequestingAgentID"].ToString(),
571 request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()));
572
573 if (group == null)
574 NullResult(result, "Internal error");
575 else
576 result["RESULT"] = GroupsDataUtils.GroupMembershipData(group);
577
578 string xmlString = ServerUtils.BuildXmlResponse(result);
579
580 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
581 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
582
583 }
584 else if (op == "ROLE" && request.ContainsKey("RoleID"))
585 {
586 m_GroupsService.SetAgentActiveGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
587 new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
588 result["RESULT"] = "true";
589 }
590
591 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
592 }
593
594 }
595
596 byte[] HandleUpdateMembership(Dictionary<string, object> request)
597 {
598 Dictionary<string, object> result = new Dictionary<string, object>();
599
600 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID") ||
601 !request.ContainsKey("AcceptNotices") || !request.ContainsKey("ListInProfile"))
602 NullResult(result, "Bad network data");
603
604 else
605 {
606 m_GroupsService.UpdateMembership(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()),
607 bool.Parse(request["AcceptNotices"].ToString()), bool.Parse(request["ListInProfile"].ToString()));
608
609 result["RESULT"] = "true";
610 }
611
612 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
613 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
614 }
615
616 byte[] HandleInvite(Dictionary<string, object> request)
617 {
618 Dictionary<string, object> result = new Dictionary<string, object>();
619
620 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("InviteID"))
621 {
622 NullResult(result, "Bad network data");
623 string xmlString = ServerUtils.BuildXmlResponse(result);
624 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
625 }
626 else
627 {
628 string op = request["OP"].ToString();
629 string reason = string.Empty;
630
631 if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID"))
632 {
633 bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(),
634 new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()),
635 new UUID(request["RoleID"].ToString()), request["AgentID"].ToString());
636
637 result["RESULT"] = success.ToString();
638 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
639
640 }
641 else if (op == "DELETE")
642 {
643 m_GroupsService.RemoveAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString()));
644 result["RESULT"] = "true";
645 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
646 }
647 else if (op == "GET")
648 {
649 GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(),
650 new UUID(request["InviteID"].ToString()));
651
652 result["RESULT"] = GroupsDataUtils.GroupInviteInfo(invite);
653 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
654 }
655
656 NullResult(result, "Bad OP in request");
657 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
658 }
659
660 }
661
662 byte[] HandleAddNotice(Dictionary<string, object> request)
663 {
664 Dictionary<string, object> result = new Dictionary<string, object>();
665
666 if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
667 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
668 !request.ContainsKey("HasAttachment"))
669 NullResult(result, "Bad network data");
670
671 else
672 {
673
674 bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
675 byte attType = 0;
676 string attName = string.Empty;
677 string attOwner = string.Empty;
678 UUID attItem = UUID.Zero;
679 if (request.ContainsKey("AttachmentType"))
680 attType = byte.Parse(request["AttachmentType"].ToString());
681 if (request.ContainsKey("AttachmentName"))
682 attName = request["AttachmentName"].ToString();
683 if (request.ContainsKey("AttachmentItemID"))
684 attItem = new UUID(request["AttachmentItemID"].ToString());
685 if (request.ContainsKey("AttachmentOwnerID"))
686 attOwner = request["AttachmentOwnerID"].ToString();
687
688 bool success = m_GroupsService.AddGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
689 new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
690 request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
691
692 result["RESULT"] = success.ToString();
693 }
694
695 string xmlString = ServerUtils.BuildXmlResponse(result);
696
697 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
698 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
699 }
700
701 byte[] HandleGetNotices(Dictionary<string, object> request)
702 {
703 Dictionary<string, object> result = new Dictionary<string, object>();
704
705 if (!request.ContainsKey("RequestingAgentID"))
706 NullResult(result, "Bad network data");
707
708 else if (request.ContainsKey("NoticeID")) // just one
709 {
710 GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["NoticeID"].ToString()));
711
712 if (notice == null)
713 NullResult(result, "NO such notice");
714 else
715 result["RESULT"] = GroupsDataUtils.GroupNoticeInfo(notice);
716
717 }
718 else if (request.ContainsKey("GroupID")) // all notices for group
719 {
720 List<ExtendedGroupNoticeData> notices = m_GroupsService.GetGroupNotices(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()));
721
722 if (notices == null || (notices != null && notices.Count == 0))
723 NullResult(result, "No notices");
724 else
725 {
726 Dictionary<string, object> dict = new Dictionary<string, object>();
727 int i = 0;
728 foreach (ExtendedGroupNoticeData n in notices)
729 dict["n-" + i++] = GroupsDataUtils.GroupNoticeData(n);
730
731 result["RESULT"] = dict;
732 }
733
734 }
735 else
736 NullResult(result, "Bad OP in request");
737
738 string xmlString = ServerUtils.BuildXmlResponse(result);
739 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
740 }
741
742
743 #region Helpers
744
745 private void NullResult(Dictionary<string, object> result, string reason)
746 {
747 result["RESULT"] = "NULL";
748 result["REASON"] = reason;
749 }
750
751 private byte[] FailureResult()
752 {
753 Dictionary<string, object> result = new Dictionary<string, object>();
754 NullResult(result, "Unknown method");
755 string xmlString = ServerUtils.BuildXmlResponse(result);
756 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
757 }
758 #endregion
759 }
760}
diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs
new file mode 100644
index 0000000..e7d38c2
--- /dev/null
+++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs
@@ -0,0 +1,831 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35
36using OpenMetaverse;
37
38namespace OpenSim.Groups
39{
40 public delegate ExtendedGroupRecord GroupRecordDelegate();
41 public delegate GroupMembershipData GroupMembershipDelegate();
42 public delegate List<GroupMembershipData> GroupMembershipListDelegate();
43 public delegate List<ExtendedGroupMembersData> GroupMembersListDelegate();
44 public delegate List<GroupRolesData> GroupRolesListDelegate();
45 public delegate List<ExtendedGroupRoleMembersData> RoleMembersListDelegate();
46 public delegate GroupNoticeInfo NoticeDelegate();
47 public delegate List<ExtendedGroupNoticeData> NoticeListDelegate();
48 public delegate void VoidDelegate();
49 public delegate bool BooleanDelegate();
50
51 public class RemoteConnectorCacheWrapper
52 {
53 private ForeignImporter m_ForeignImporter;
54
55 private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
56 private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes
57
58 // This all important cache cahces objects of different types:
59 // group-<GroupID> or group-<Name> => ExtendedGroupRecord
60 // active-<AgentID> => GroupMembershipData
61 // membership-<AgentID>-<GroupID> => GroupMembershipData
62 // memberships-<AgentID> => List<GroupMembershipData>
63 // members-<RequestingAgentID>-<GroupID> => List<ExtendedGroupMembersData>
64 // role-<RoleID> => GroupRolesData
65 // roles-<GroupID> => List<GroupRolesData> ; all roles in the group
66 // roles-<GroupID>-<AgentID> => List<GroupRolesData> ; roles that the agent has
67 // rolemembers-<RequestingAgentID>-<GroupID> => List<ExtendedGroupRoleMembersData>
68 // notice-<noticeID> => GroupNoticeInfo
69 // notices-<GroupID> => List<ExtendedGroupNoticeData>
70 private ExpiringCache<string, object> m_Cache = new ExpiringCache<string, object>();
71
72 public RemoteConnectorCacheWrapper(IUserManagement uman)
73 {
74 m_ForeignImporter = new ForeignImporter(uman);
75 }
76
77 public UUID CreateGroup(UUID RequestingAgentID, GroupRecordDelegate d)
78 {
79 //m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
80 //reason = string.Empty;
81
82 //ExtendedGroupRecord group = m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
83 // membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
84 ExtendedGroupRecord group = d();
85
86 if (group == null)
87 return UUID.Zero;
88
89 if (group.GroupID != UUID.Zero)
90 lock (m_Cache)
91 {
92 m_Cache.Add("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
93 if (m_Cache.Contains("memberships-" + RequestingAgentID.ToString()))
94 m_Cache.Remove("memberships-" + RequestingAgentID.ToString());
95 }
96
97 return group.GroupID;
98 }
99
100 public bool UpdateGroup(UUID groupID, GroupRecordDelegate d)
101 {
102 //reason = string.Empty;
103 //ExtendedGroupRecord group = m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
104 ExtendedGroupRecord group = d();
105
106 if (group != null && group.GroupID != UUID.Zero)
107 lock (m_Cache)
108 m_Cache.AddOrUpdate("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
109 return true;
110 }
111
112 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, GroupRecordDelegate d)
113 {
114 //if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
115 // return null;
116
117 object group = null;
118 bool firstCall = false;
119 string cacheKey = "group-";
120 if (GroupID != UUID.Zero)
121 cacheKey += GroupID.ToString();
122 else
123 cacheKey += GroupName;
124
125 //m_log.DebugFormat("[XXX]: GetGroupRecord {0}", cacheKey);
126
127 while (true)
128 {
129 lock (m_Cache)
130 {
131 if (m_Cache.TryGetValue(cacheKey, out group))
132 {
133 //m_log.DebugFormat("[XXX]: GetGroupRecord {0} cached!", cacheKey);
134 return (ExtendedGroupRecord)group;
135 }
136
137 // not cached
138 if (!m_ActiveRequests.ContainsKey(cacheKey))
139 {
140 m_ActiveRequests.Add(cacheKey, true);
141 firstCall = true;
142 }
143 }
144
145 if (firstCall)
146 {
147 //group = m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
148 group = d();
149
150 lock (m_Cache)
151 {
152 m_Cache.AddOrUpdate(cacheKey, group, GROUPS_CACHE_TIMEOUT);
153 m_ActiveRequests.Remove(cacheKey);
154 return (ExtendedGroupRecord)group;
155 }
156 }
157 else
158 Thread.Sleep(50);
159 }
160 }
161
162 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, GroupMembershipDelegate d)
163 {
164 GroupMembershipData membership = d();
165 if (membership == null)
166 return false;
167
168 lock (m_Cache)
169 {
170 // first, remove everything! add a user is a heavy-duty op
171 m_Cache.Clear();
172
173 m_Cache.AddOrUpdate("active-" + AgentID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
174 m_Cache.AddOrUpdate("membership-" + AgentID.ToString() + "-" + GroupID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
175 }
176
177
178 return true;
179 }
180
181 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, VoidDelegate d)
182 {
183 d();
184
185 lock (m_Cache)
186 {
187 string cacheKey = "active-" + AgentID.ToString();
188 if (m_Cache.Contains(cacheKey))
189 m_Cache.Remove(cacheKey);
190
191 cacheKey = "memberships-" + AgentID.ToString();
192 if (m_Cache.Contains(cacheKey))
193 m_Cache.Remove(cacheKey);
194
195 cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
196 if (m_Cache.Contains(cacheKey))
197 m_Cache.Remove(cacheKey);
198
199 cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
200 if (m_Cache.Contains(cacheKey))
201 m_Cache.Remove(cacheKey);
202
203 cacheKey = "roles-" + "-" + GroupID.ToString() + "-" + AgentID.ToString();
204 if (m_Cache.Contains(cacheKey))
205 m_Cache.Remove(cacheKey);
206 }
207 }
208
209 public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d)
210 {
211 GroupMembershipData activeGroup = d();
212 if (activeGroup != null)
213 {
214 string cacheKey = "active-" + AgentID.ToString();
215 lock (m_Cache)
216 if (m_Cache.Contains(cacheKey))
217 m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT);
218 }
219 }
220
221 public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d)
222 {
223 object membership = null;
224 bool firstCall = false;
225 string cacheKey = "active-" + AgentID.ToString();
226
227 //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0}", cacheKey);
228
229 while (true)
230 {
231 lock (m_Cache)
232 {
233 if (m_Cache.TryGetValue(cacheKey, out membership))
234 {
235 //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0} cached!", cacheKey);
236 return (ExtendedGroupMembershipData)membership;
237 }
238
239 // not cached
240 if (!m_ActiveRequests.ContainsKey(cacheKey))
241 {
242 m_ActiveRequests.Add(cacheKey, true);
243 firstCall = true;
244 }
245 }
246
247 if (firstCall)
248 {
249 membership = d();
250
251 lock (m_Cache)
252 {
253 m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
254 m_ActiveRequests.Remove(cacheKey);
255 return (ExtendedGroupMembershipData)membership;
256 }
257 }
258 else
259 Thread.Sleep(50);
260 }
261
262 }
263
264 public ExtendedGroupMembershipData GetAgentGroupMembership(string AgentID, UUID GroupID, GroupMembershipDelegate d)
265 {
266 object membership = null;
267 bool firstCall = false;
268 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
269
270 //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
271
272 while (true)
273 {
274 lock (m_Cache)
275 {
276 if (m_Cache.TryGetValue(cacheKey, out membership))
277 {
278 //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
279 return (ExtendedGroupMembershipData)membership;
280 }
281
282 // not cached
283 if (!m_ActiveRequests.ContainsKey(cacheKey))
284 {
285 m_ActiveRequests.Add(cacheKey, true);
286 firstCall = true;
287 }
288 }
289
290 if (firstCall)
291 {
292 membership = d();
293 lock (m_Cache)
294 {
295 m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
296 m_ActiveRequests.Remove(cacheKey);
297 return (ExtendedGroupMembershipData)membership;
298 }
299 }
300 else
301 Thread.Sleep(50);
302 }
303 }
304
305 public List<GroupMembershipData> GetAgentGroupMemberships(string AgentID, GroupMembershipListDelegate d)
306 {
307 object memberships = null;
308 bool firstCall = false;
309 string cacheKey = "memberships-" + AgentID.ToString();
310
311 //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0}", cacheKey);
312
313 while (true)
314 {
315 lock (m_Cache)
316 {
317 if (m_Cache.TryGetValue(cacheKey, out memberships))
318 {
319 //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0} cached!", cacheKey);
320 return (List<GroupMembershipData>)memberships;
321 }
322
323 // not cached
324 if (!m_ActiveRequests.ContainsKey(cacheKey))
325 {
326 m_ActiveRequests.Add(cacheKey, true);
327 firstCall = true;
328 }
329 }
330
331 if (firstCall)
332 {
333 memberships = d();
334 lock (m_Cache)
335 {
336 m_Cache.AddOrUpdate(cacheKey, memberships, GROUPS_CACHE_TIMEOUT);
337 m_ActiveRequests.Remove(cacheKey);
338 return (List<GroupMembershipData>)memberships;
339 }
340 }
341 else
342 Thread.Sleep(50);
343 }
344 }
345
346 public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, GroupMembersListDelegate d)
347 {
348 object members = null;
349 bool firstCall = false;
350 // we need to key in also on the requester, because different ppl have different view privileges
351 string cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
352
353 //m_log.DebugFormat("[XXX]: GetGroupMembers {0}", cacheKey);
354
355 while (true)
356 {
357 lock (m_Cache)
358 {
359 if (m_Cache.TryGetValue(cacheKey, out members))
360 {
361 List<ExtendedGroupMembersData> xx = (List<ExtendedGroupMembersData>)members;
362 return xx.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
363 }
364
365 // not cached
366 if (!m_ActiveRequests.ContainsKey(cacheKey))
367 {
368 m_ActiveRequests.Add(cacheKey, true);
369 firstCall = true;
370 }
371 }
372
373 if (firstCall)
374 {
375 List<ExtendedGroupMembersData> _members = d();
376
377 if (_members != null && _members.Count > 0)
378 members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
379 else
380 members = new List<GroupMembersData>();
381
382 lock (m_Cache)
383 {
384 //m_Cache.AddOrUpdate(cacheKey, members, GROUPS_CACHE_TIMEOUT);
385 m_Cache.AddOrUpdate(cacheKey, _members, GROUPS_CACHE_TIMEOUT);
386 m_ActiveRequests.Remove(cacheKey);
387
388 return (List<GroupMembersData>)members;
389 }
390 }
391 else
392 Thread.Sleep(50);
393 }
394 }
395
396 public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d)
397 {
398 if (d())
399 {
400 GroupRolesData role = new GroupRolesData();
401 role.Description = description;
402 role.Members = 0;
403 role.Name = name;
404 role.Powers = powers;
405 role.RoleID = roleID;
406 role.Title = title;
407
408 lock (m_Cache)
409 {
410 m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT);
411
412 // also remove this list
413 if (m_Cache.Contains("roles-" + groupID.ToString()))
414 m_Cache.Remove("roles-" + groupID.ToString());
415
416 }
417
418 return true;
419 }
420
421 return false;
422 }
423
424 public bool UpdateGroupRole(UUID groupID, UUID roleID, string name, string description, string title, ulong powers, BooleanDelegate d)
425 {
426 if (d())
427 {
428 object role;
429 lock (m_Cache)
430 if (m_Cache.TryGetValue("role-" + roleID.ToString(), out role))
431 {
432 GroupRolesData r = (GroupRolesData)role;
433 r.Description = description;
434 r.Name = name;
435 r.Powers = powers;
436 r.Title = title;
437
438 m_Cache.Update("role-" + roleID.ToString(), r, GROUPS_CACHE_TIMEOUT);
439 }
440 return true;
441 }
442 else
443 {
444 lock (m_Cache)
445 {
446 if (m_Cache.Contains("role-" + roleID.ToString()))
447 m_Cache.Remove("role-" + roleID.ToString());
448
449 // also remove these lists, because they will have an outdated role
450 if (m_Cache.Contains("roles-" + groupID.ToString()))
451 m_Cache.Remove("roles-" + groupID.ToString());
452
453 }
454
455 return false;
456 }
457 }
458
459 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, VoidDelegate d)
460 {
461 d();
462
463 lock (m_Cache)
464 {
465 if (m_Cache.Contains("role-" + roleID.ToString()))
466 m_Cache.Remove("role-" + roleID.ToString());
467
468 // also remove the list, because it will have an removed role
469 if (m_Cache.Contains("roles-" + groupID.ToString()))
470 m_Cache.Remove("roles-" + groupID.ToString());
471
472 if (m_Cache.Contains("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString()))
473 m_Cache.Remove("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString());
474
475 if (m_Cache.Contains("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString()))
476 m_Cache.Remove("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString());
477 }
478 }
479
480 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, GroupRolesListDelegate d)
481 {
482 object roles = null;
483 bool firstCall = false;
484 string cacheKey = "roles-" + GroupID.ToString();
485
486 while (true)
487 {
488 lock (m_Cache)
489 {
490 if (m_Cache.TryGetValue(cacheKey, out roles))
491 return (List<GroupRolesData>)roles;
492
493 // not cached
494 if (!m_ActiveRequests.ContainsKey(cacheKey))
495 {
496 m_ActiveRequests.Add(cacheKey, true);
497 firstCall = true;
498 }
499 }
500
501 if (firstCall)
502 {
503 roles = d();
504 if (roles != null)
505 {
506 lock (m_Cache)
507 {
508 m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
509 m_ActiveRequests.Remove(cacheKey);
510 return (List<GroupRolesData>)roles;
511 }
512 }
513 }
514 else
515 Thread.Sleep(50);
516 }
517 }
518
519 public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, RoleMembersListDelegate d)
520 {
521 object rmembers = null;
522 bool firstCall = false;
523 // we need to key in also on the requester, because different ppl have different view privileges
524 string cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
525
526 //m_log.DebugFormat("[XXX]: GetGroupRoleMembers {0}", cacheKey);
527 while (true)
528 {
529 lock (m_Cache)
530 {
531 if (m_Cache.TryGetValue(cacheKey, out rmembers))
532 {
533 List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)rmembers;
534 return xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
535 }
536
537 // not cached
538 if (!m_ActiveRequests.ContainsKey(cacheKey))
539 {
540 m_ActiveRequests.Add(cacheKey, true);
541 firstCall = true;
542 }
543 }
544
545 if (firstCall)
546 {
547 List<ExtendedGroupRoleMembersData> _rmembers = d();
548
549 if (_rmembers != null && _rmembers.Count > 0)
550 rmembers = _rmembers.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
551 else
552 rmembers = new List<GroupRoleMembersData>();
553
554 lock (m_Cache)
555 {
556 // For some strange reason, when I cache the list of GroupRoleMembersData,
557 // it gets emptied out. The TryGet gets an empty list...
558 //m_Cache.AddOrUpdate(cacheKey, rmembers, GROUPS_CACHE_TIMEOUT);
559 // Caching the list of ExtendedGroupRoleMembersData doesn't show that issue
560 // I don't get it.
561 m_Cache.AddOrUpdate(cacheKey, _rmembers, GROUPS_CACHE_TIMEOUT);
562 m_ActiveRequests.Remove(cacheKey);
563 return (List<GroupRoleMembersData>)rmembers;
564 }
565 }
566 else
567 Thread.Sleep(50);
568 }
569 }
570
571 public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
572 {
573 if (d())
574 {
575 lock (m_Cache)
576 {
577 // update the cached role
578 string cacheKey = "role-" + RoleID.ToString();
579 object obj;
580 if (m_Cache.TryGetValue(cacheKey, out obj))
581 {
582 GroupRolesData r = (GroupRolesData)obj;
583 r.Members++;
584 }
585
586 // add this agent to the list of role members
587 cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
588 if (m_Cache.TryGetValue(cacheKey, out obj))
589 {
590 try
591 {
592 // This may throw an exception, in which case the agentID is not a UUID but a full ID
593 // In that case, let's just remove the whoe things from the cache
594 UUID id = new UUID(AgentID);
595 List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)obj;
596 List<GroupRoleMembersData> rmlist = xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
597 GroupRoleMembersData rm = new GroupRoleMembersData();
598 rm.MemberID = id;
599 rm.RoleID = RoleID;
600 rmlist.Add(rm);
601 }
602 catch
603 {
604 m_Cache.Remove(cacheKey);
605 }
606 }
607
608 // Remove the cached info about this agent's roles
609 // because we don't have enough local info about the new role
610 cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
611 if (m_Cache.Contains(cacheKey))
612 m_Cache.Remove(cacheKey);
613
614 }
615 }
616 }
617
618 public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
619 {
620 if (d())
621 {
622 lock (m_Cache)
623 {
624 // update the cached role
625 string cacheKey = "role-" + RoleID.ToString();
626 object obj;
627 if (m_Cache.TryGetValue(cacheKey, out obj))
628 {
629 GroupRolesData r = (GroupRolesData)obj;
630 r.Members--;
631 }
632
633 cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
634 if (m_Cache.Contains(cacheKey))
635 m_Cache.Remove(cacheKey);
636
637 cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
638 if (m_Cache.Contains(cacheKey))
639 m_Cache.Remove(cacheKey);
640 }
641 }
642 }
643
644 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID, GroupRolesListDelegate d)
645 {
646 object roles = null;
647 bool firstCall = false;
648 string cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
649
650 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
651
652 while (true)
653 {
654 lock (m_Cache)
655 {
656 if (m_Cache.TryGetValue(cacheKey, out roles))
657 {
658 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0} cached!", cacheKey);
659 return (List<GroupRolesData>)roles;
660 }
661
662 // not cached
663 if (!m_ActiveRequests.ContainsKey(cacheKey))
664 {
665 m_ActiveRequests.Add(cacheKey, true);
666 firstCall = true;
667 }
668 }
669
670 if (firstCall)
671 {
672 roles = d();
673 lock (m_Cache)
674 {
675 m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
676 m_ActiveRequests.Remove(cacheKey);
677 return (List<GroupRolesData>)roles;
678 }
679 }
680 else
681 Thread.Sleep(50);
682 }
683 }
684
685 public void SetAgentActiveGroupRole(string AgentID, UUID GroupID, VoidDelegate d)
686 {
687 d();
688
689 lock (m_Cache)
690 {
691 // Invalidate cached info, because it has ActiveRoleID and Powers
692 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
693 if (m_Cache.Contains(cacheKey))
694 m_Cache.Remove(cacheKey);
695
696 cacheKey = "memberships-" + AgentID.ToString();
697 if (m_Cache.Contains(cacheKey))
698 m_Cache.Remove(cacheKey);
699 }
700 }
701
702 public void UpdateMembership(string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile, VoidDelegate d)
703 {
704 d();
705
706 lock (m_Cache)
707 {
708 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
709 if (m_Cache.Contains(cacheKey))
710 m_Cache.Remove(cacheKey);
711
712 cacheKey = "memberships-" + AgentID.ToString();
713 if (m_Cache.Contains(cacheKey))
714 m_Cache.Remove(cacheKey);
715
716 cacheKey = "active-" + AgentID.ToString();
717 object m = null;
718 if (m_Cache.TryGetValue(cacheKey, out m))
719 {
720 GroupMembershipData membership = (GroupMembershipData)m;
721 membership.ListInProfile = ListInProfile;
722 membership.AcceptNotices = AcceptNotices;
723 }
724 }
725 }
726
727 public bool AddGroupNotice(UUID groupID, UUID noticeID, GroupNoticeInfo notice, BooleanDelegate d)
728 {
729 if (d())
730 {
731 lock (m_Cache)
732 {
733 m_Cache.AddOrUpdate("notice-" + noticeID.ToString(), notice, GROUPS_CACHE_TIMEOUT);
734 string cacheKey = "notices-" + groupID.ToString();
735 if (m_Cache.Contains(cacheKey))
736 m_Cache.Remove(cacheKey);
737
738 }
739
740 return true;
741 }
742
743 return false;
744 }
745
746 public GroupNoticeInfo GetGroupNotice(UUID noticeID, NoticeDelegate d)
747 {
748 object notice = null;
749 bool firstCall = false;
750 string cacheKey = "notice-" + noticeID.ToString();
751
752 //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
753
754 while (true)
755 {
756 lock (m_Cache)
757 {
758 if (m_Cache.TryGetValue(cacheKey, out notice))
759 {
760 return (GroupNoticeInfo)notice;
761 }
762
763 // not cached
764 if (!m_ActiveRequests.ContainsKey(cacheKey))
765 {
766 m_ActiveRequests.Add(cacheKey, true);
767 firstCall = true;
768 }
769 }
770
771 if (firstCall)
772 {
773 GroupNoticeInfo _notice = d();
774
775 lock (m_Cache)
776 {
777 m_Cache.AddOrUpdate(cacheKey, _notice, GROUPS_CACHE_TIMEOUT);
778 m_ActiveRequests.Remove(cacheKey);
779 return _notice;
780 }
781 }
782 else
783 Thread.Sleep(50);
784 }
785 }
786
787 public List<ExtendedGroupNoticeData> GetGroupNotices(UUID GroupID, NoticeListDelegate d)
788 {
789 object notices = null;
790 bool firstCall = false;
791 string cacheKey = "notices-" + GroupID.ToString();
792
793 //m_log.DebugFormat("[XXX]: GetGroupNotices {0}", cacheKey);
794
795 while (true)
796 {
797 lock (m_Cache)
798 {
799 if (m_Cache.TryGetValue(cacheKey, out notices))
800 {
801 //m_log.DebugFormat("[XXX]: GetGroupNotices {0} cached!", cacheKey);
802 return (List<ExtendedGroupNoticeData>)notices;
803 }
804
805 // not cached
806 if (!m_ActiveRequests.ContainsKey(cacheKey))
807 {
808 m_ActiveRequests.Add(cacheKey, true);
809 firstCall = true;
810 }
811 }
812
813 if (firstCall)
814 {
815 notices = d();
816
817 lock (m_Cache)
818 {
819 m_Cache.AddOrUpdate(cacheKey, notices, GROUPS_CACHE_TIMEOUT);
820 m_ActiveRequests.Remove(cacheKey);
821 return (List<ExtendedGroupNoticeData>)notices;
822 }
823 }
824 else
825 Thread.Sleep(50);
826 }
827 }
828
829
830 }
831}
diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs
new file mode 100644
index 0000000..0668870
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/GroupsService.cs
@@ -0,0 +1,1020 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Nini.Config;
34
35using OpenMetaverse;
36using OpenSim.Data;
37using OpenSim.Framework;
38using OpenSim.Services.Interfaces;
39
40namespace OpenSim.Groups
41{
42 public class GroupsService : GroupsServiceBase
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 public const GroupPowers DefaultEveryonePowers = GroupPowers.AllowSetHome |
47 GroupPowers.Accountable |
48 GroupPowers.JoinChat |
49 GroupPowers.AllowVoiceChat |
50 GroupPowers.ReceiveNotices |
51 GroupPowers.StartProposal |
52 GroupPowers.VoteOnProposal;
53
54 public const GroupPowers OwnerPowers = GroupPowers.Accountable |
55 GroupPowers.AllowEditLand |
56 GroupPowers.AllowFly |
57 GroupPowers.AllowLandmark |
58 GroupPowers.AllowRez |
59 GroupPowers.AllowSetHome |
60 GroupPowers.AllowVoiceChat |
61 GroupPowers.AssignMember |
62 GroupPowers.AssignMemberLimited |
63 GroupPowers.ChangeActions |
64 GroupPowers.ChangeIdentity |
65 GroupPowers.ChangeMedia |
66 GroupPowers.ChangeOptions |
67 GroupPowers.CreateRole |
68 GroupPowers.DeedObject |
69 GroupPowers.DeleteRole |
70 GroupPowers.Eject |
71 GroupPowers.FindPlaces |
72 GroupPowers.Invite |
73 GroupPowers.JoinChat |
74 GroupPowers.LandChangeIdentity |
75 GroupPowers.LandDeed |
76 GroupPowers.LandDivideJoin |
77 GroupPowers.LandEdit |
78 GroupPowers.LandEjectAndFreeze |
79 GroupPowers.LandGardening |
80 GroupPowers.LandManageAllowed |
81 GroupPowers.LandManageBanned |
82 GroupPowers.LandManagePasses |
83 GroupPowers.LandOptions |
84 GroupPowers.LandRelease |
85 GroupPowers.LandSetSale |
86 GroupPowers.ModerateChat |
87 GroupPowers.ObjectManipulate |
88 GroupPowers.ObjectSetForSale |
89 GroupPowers.ReceiveNotices |
90 GroupPowers.RemoveMember |
91 GroupPowers.ReturnGroupOwned |
92 GroupPowers.ReturnGroupSet |
93 GroupPowers.ReturnNonGroup |
94 GroupPowers.RoleProperties |
95 GroupPowers.SendNotices |
96 GroupPowers.SetLandingPoint |
97 GroupPowers.StartProposal |
98 GroupPowers.VoteOnProposal;
99
100 #region Daily Cleanup
101
102 private Timer m_CleanupTimer;
103
104 public GroupsService(IConfigSource config, string configName)
105 : base(config, configName)
106 {
107 }
108
109 public GroupsService(IConfigSource config)
110 : this(config, string.Empty)
111 {
112 // Once a day
113 m_CleanupTimer = new Timer(24 * 60 * 60 * 1000);
114 m_CleanupTimer.AutoReset = true;
115 m_CleanupTimer.Elapsed += new ElapsedEventHandler(m_CleanupTimer_Elapsed);
116 m_CleanupTimer.Enabled = true;
117 m_CleanupTimer.Start();
118 }
119
120 private void m_CleanupTimer_Elapsed(object sender, ElapsedEventArgs e)
121 {
122 m_Database.DeleteOldNotices();
123 m_Database.DeleteOldInvites();
124 }
125
126 #endregion
127
128 public UUID CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
129 bool allowPublish, bool maturePublish, UUID founderID, out string reason)
130 {
131 reason = string.Empty;
132
133 // Create the group
134 GroupData data = new GroupData();
135 data.GroupID = UUID.Random();
136 data.Data = new Dictionary<string, string>();
137 data.Data["Name"] = name;
138 data.Data["Charter"] = charter;
139 data.Data["InsigniaID"] = insigniaID.ToString();
140 data.Data["FounderID"] = founderID.ToString();
141 data.Data["MembershipFee"] = membershipFee.ToString();
142 data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0";
143 data.Data["ShowInList"] = showInList ? "1" : "0";
144 data.Data["AllowPublish"] = allowPublish ? "1" : "0";
145 data.Data["MaturePublish"] = maturePublish ? "1" : "0";
146 data.Data["OwnerRoleID"] = UUID.Random().ToString();
147
148 if (!m_Database.StoreGroup(data))
149 return UUID.Zero;
150
151 // Create Everyone role
152 _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, UUID.Zero, "Everyone", "Everyone in the group", "Member of " + name, (ulong)DefaultEveryonePowers, true);
153
154 // Create Owner role
155 UUID roleID = UUID.Random();
156 _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, roleID, "Owners", "Owners of the group", "Owner of " + name, (ulong)OwnerPowers, true);
157
158 // Add founder to group
159 _AddAgentToGroup(RequestingAgentID, founderID.ToString(), data.GroupID, roleID);
160
161 return data.GroupID;
162 }
163
164 public void UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
165 {
166 GroupData data = m_Database.RetrieveGroup(groupID);
167 if (data == null)
168 return;
169
170 // Check perms
171 if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions))
172 {
173 m_log.DebugFormat("[Groups]: ({0}) Attempt at updating group {1} denied because of lack of permission", RequestingAgentID, groupID);
174 return;
175 }
176
177 data.GroupID = groupID;
178 data.Data["Charter"] = charter;
179 data.Data["ShowInList"] = showInList ? "1" : "0";
180 data.Data["InsigniaID"] = insigniaID.ToString();
181 data.Data["MembershipFee"] = membershipFee.ToString();
182 data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0";
183 data.Data["AllowPublish"] = allowPublish ? "1" : "0";
184 data.Data["MaturePublish"] = maturePublish ? "1" : "0";
185
186 m_Database.StoreGroup(data);
187
188 }
189
190 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID)
191 {
192 GroupData data = m_Database.RetrieveGroup(GroupID);
193
194 return _GroupDataToRecord(data);
195 }
196
197 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, string GroupName)
198 {
199 GroupData data = m_Database.RetrieveGroup(GroupName);
200
201 return _GroupDataToRecord(data);
202 }
203
204 public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
205 {
206 List<DirGroupsReplyData> groups = new List<DirGroupsReplyData>();
207
208 GroupData[] data = m_Database.RetrieveGroups(search);
209
210 if (data != null && data.Length > 0)
211 {
212 foreach (GroupData d in data)
213 {
214 // Don't list group proxies
215 if (d.Data.ContainsKey("Location") && d.Data["Location"] != string.Empty)
216 continue;
217
218 DirGroupsReplyData g = new DirGroupsReplyData();
219 g.groupID = d.GroupID;
220
221 if (d.Data.ContainsKey("Name"))
222 g.groupName = d.Data["Name"];
223 else
224 m_log.DebugFormat("[Groups]: Key Name not found");
225
226 g.members = m_Database.MemberCount(d.GroupID);
227
228 groups.Add(g);
229 }
230 }
231
232 return groups;
233 }
234
235 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
236 {
237 List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
238
239 GroupData group = m_Database.RetrieveGroup(GroupID);
240 if (group == null)
241 return members;
242
243 UUID ownerRoleID = new UUID(group.Data["OwnerRoleID"]);
244
245 RoleData[] roles = m_Database.RetrieveRoles(GroupID);
246 if (roles == null)
247 // something wrong with this group
248 return members;
249 List<RoleData> rolesList = new List<RoleData>(roles);
250
251 // Is the requester a member of the group?
252 bool isInGroup = false;
253 if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
254 isInGroup = true;
255
256 if (!isInGroup) // reduce the roles to the visible ones
257 rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
258
259 MembershipData[] datas = m_Database.RetrieveMembers(GroupID);
260 if (datas == null || (datas != null && datas.Length == 0))
261 return members;
262
263 // OK, we have everything we need
264
265 foreach (MembershipData d in datas)
266 {
267 RoleMembershipData[] rolememberships = m_Database.RetrieveMemberRoles(GroupID, d.PrincipalID);
268 List<RoleMembershipData> rolemembershipsList = new List<RoleMembershipData>(rolememberships);
269
270 ExtendedGroupMembersData m = new ExtendedGroupMembersData();
271
272 // What's this person's current role in the group?
273 UUID selectedRole = new UUID(d.Data["SelectedRoleID"]);
274 RoleData selected = rolesList.Find(r => r.RoleID == selectedRole);
275
276 if (selected != null)
277 {
278 m.Title = selected.Data["Title"];
279 m.AgentPowers = UInt64.Parse(selected.Data["Powers"]);
280
281 m.AgentID = d.PrincipalID;
282 m.AcceptNotices = d.Data["AcceptNotices"] == "1" ? true : false;
283 m.Contribution = Int32.Parse(d.Data["Contribution"]);
284 m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false;
285
286 // Is this person an owner of the group?
287 m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false;
288
289 members.Add(m);
290 }
291 }
292
293 return members;
294 }
295
296 public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
297 {
298 reason = string.Empty;
299 // check that the requesting agent has permissions to add role
300 if (!HasPower(RequestingAgentID, groupID, GroupPowers.CreateRole))
301 {
302 m_log.DebugFormat("[Groups]: ({0}) Attempt at creating role in group {1} denied because of lack of permission", RequestingAgentID, groupID);
303 reason = "Insufficient permission to create role";
304 return false;
305 }
306
307 return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, true);
308
309 }
310
311 public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
312 {
313 // check perms
314 if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions))
315 {
316 m_log.DebugFormat("[Groups]: ({0}) Attempt at changing role in group {1} denied because of lack of permission", RequestingAgentID, groupID);
317 return false;
318 }
319
320 return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, false);
321 }
322
323 public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
324 {
325 // check perms
326 if (!HasPower(RequestingAgentID, groupID, GroupPowers.DeleteRole))
327 {
328 m_log.DebugFormat("[Groups]: ({0}) Attempt at deleting role from group {1} denied because of lack of permission", RequestingAgentID, groupID);
329 return;
330 }
331
332 // Can't delete Everyone and Owners roles
333 if (roleID == UUID.Zero)
334 {
335 m_log.DebugFormat("[Groups]: Attempt at deleting Everyone role from group {0} denied", groupID);
336 return;
337 }
338
339 GroupData group = m_Database.RetrieveGroup(groupID);
340 if (group == null)
341 {
342 m_log.DebugFormat("[Groups]: Attempt at deleting role from non-existing group {0}", groupID);
343 return;
344 }
345
346 if (roleID == new UUID(group.Data["OwnerRoleID"]))
347 {
348 m_log.DebugFormat("[Groups]: Attempt at deleting Owners role from group {0} denied", groupID);
349 return;
350 }
351
352 _RemoveGroupRole(groupID, roleID);
353 }
354
355 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
356 {
357 // TODO: check perms
358 return _GetGroupRoles(GroupID);
359 }
360
361 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
362 {
363 // TODO: check perms
364
365 // Is the requester a member of the group?
366 bool isInGroup = false;
367 if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
368 isInGroup = true;
369
370 return _GetGroupRoleMembers(GroupID, isInGroup);
371 }
372
373 public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
374 {
375 reason = string.Empty;
376
377 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token);
378
379 return true;
380 }
381
382 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
383 {
384 // check perms
385 if (RequestingAgentID != AgentID && !HasPower(RequestingAgentID, GroupID, GroupPowers.Eject))
386 return;
387
388 _RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
389 }
390
391 public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
392 {
393 // Check whether the invitee is already a member of the group
394 MembershipData m = m_Database.RetrieveMember(groupID, agentID);
395 if (m != null)
396 return false;
397
398 // Check permission to invite
399 if (!HasPower(RequestingAgentID, groupID, GroupPowers.Invite))
400 {
401 m_log.DebugFormat("[Groups]: ({0}) Attempt at inviting to group {1} denied because of lack of permission", RequestingAgentID, groupID);
402 return false;
403 }
404
405 // Check whether there are pending invitations and delete them
406 InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID);
407 if (invite != null)
408 m_Database.DeleteInvite(invite.InviteID);
409
410 invite = new InvitationData();
411 invite.InviteID = inviteID;
412 invite.PrincipalID = agentID;
413 invite.GroupID = groupID;
414 invite.RoleID = roleID;
415 invite.Data = new Dictionary<string, string>();
416
417 return m_Database.StoreInvitation(invite);
418 }
419
420 public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
421 {
422 InvitationData data = m_Database.RetrieveInvitation(inviteID);
423
424 if (data == null)
425 return null;
426
427 GroupInviteInfo inviteInfo = new GroupInviteInfo();
428 inviteInfo.AgentID = data.PrincipalID;
429 inviteInfo.GroupID = data.GroupID;
430 inviteInfo.InviteID = data.InviteID;
431 inviteInfo.RoleID = data.RoleID;
432
433 return inviteInfo;
434 }
435
436 public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
437 {
438 m_Database.DeleteInvite(inviteID);
439 }
440
441 public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
442 {
443 //if (!m_Database.CheckOwnerRole(RequestingAgentID, GroupID, RoleID))
444 // return;
445
446 // check permissions
447 bool limited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMemberLimited);
448 bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) | IsOwner(RequestingAgentID, GroupID);
449 if (!limited || !unlimited)
450 {
451 m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID);
452 return false;
453 }
454
455 // AssignMemberLimited means that the person can assign another person to the same roles that she has in the group
456 if (!unlimited && limited)
457 {
458 // check whether person's has this role
459 RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
460 if (rolemembership == null)
461 {
462 m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of limited permission", RequestingAgentID, AgentID, RoleID);
463 return false;
464 }
465 }
466
467 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
468
469 return true;
470 }
471
472 public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
473 {
474 // Don't remove from Everyone role!
475 if (RoleID == UUID.Zero)
476 return false;
477
478 // check permissions
479 bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) || IsOwner(RequestingAgentID, GroupID);
480 if (!unlimited)
481 {
482 m_log.DebugFormat("[Groups]: ({0}) Attempt at removing {1} from role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID);
483 return false;
484 }
485
486 RoleMembershipData rolemember = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
487
488 if (rolemember == null)
489 return false;
490
491 m_Database.DeleteRoleMember(rolemember);
492
493 // Find another role for this person
494 UUID newRoleID = UUID.Zero; // Everyone
495 RoleMembershipData[] rdata = m_Database.RetrieveMemberRoles(GroupID, AgentID);
496 if (rdata != null)
497 foreach (RoleMembershipData r in rdata)
498 {
499 if (r.RoleID != UUID.Zero)
500 {
501 newRoleID = r.RoleID;
502 break;
503 }
504 }
505
506 MembershipData member = m_Database.RetrieveMember(GroupID, AgentID);
507 if (member != null)
508 {
509 member.Data["SelectedRoleID"] = newRoleID.ToString();
510 m_Database.StoreMember(member);
511 }
512
513 return true;
514 }
515
516 public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
517 {
518 List<GroupRolesData> roles = new List<GroupRolesData>();
519 // TODO: check permissions
520
521 RoleMembershipData[] data = m_Database.RetrieveMemberRoles(GroupID, AgentID);
522 if (data == null || (data != null && data.Length ==0))
523 return roles;
524
525 foreach (RoleMembershipData d in data)
526 {
527 RoleData rdata = m_Database.RetrieveRole(GroupID, d.RoleID);
528 if (rdata == null) // hippos
529 continue;
530
531 GroupRolesData r = new GroupRolesData();
532 r.Name = rdata.Data["Name"];
533 r.Powers = UInt64.Parse(rdata.Data["Powers"]);
534 r.RoleID = rdata.RoleID;
535 r.Title = rdata.Data["Title"];
536
537 roles.Add(r);
538 }
539
540 return roles;
541 }
542
543 public ExtendedGroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
544 {
545 // TODO: check perms
546 PrincipalData principal = new PrincipalData();
547 principal.PrincipalID = AgentID;
548 principal.ActiveGroupID = GroupID;
549 m_Database.StorePrincipal(principal);
550
551 return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID);
552 }
553
554 public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
555 {
556 // 1. get the principal data for the active group
557 PrincipalData principal = m_Database.RetrievePrincipal(AgentID);
558 if (principal == null)
559 return null;
560
561 return GetAgentGroupMembership(RequestingAgentID, AgentID, principal.ActiveGroupID);
562 }
563
564 public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
565 {
566 return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID, null);
567 }
568
569 private ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID, MembershipData membership)
570 {
571 // 2. get the active group
572 GroupData group = m_Database.RetrieveGroup(GroupID);
573 if (group == null)
574 return null;
575
576 // 3. get the membership info if we don't have it already
577 if (membership == null)
578 {
579 membership = m_Database.RetrieveMember(group.GroupID, AgentID);
580 if (membership == null)
581 return null;
582 }
583
584 // 4. get the active role
585 UUID activeRoleID = new UUID(membership.Data["SelectedRoleID"]);
586 RoleData role = m_Database.RetrieveRole(group.GroupID, activeRoleID);
587
588 ExtendedGroupMembershipData data = new ExtendedGroupMembershipData();
589 data.AcceptNotices = membership.Data["AcceptNotices"] == "1" ? true : false;
590 data.AccessToken = membership.Data["AccessToken"];
591 data.Active = true;
592 data.ActiveRole = activeRoleID;
593 data.AllowPublish = group.Data["AllowPublish"] == "1" ? true : false;
594 data.Charter = group.Data["Charter"];
595 data.Contribution = Int32.Parse(membership.Data["Contribution"]);
596 data.FounderID = new UUID(group.Data["FounderID"]);
597 data.GroupID = new UUID(group.GroupID);
598 data.GroupName = group.Data["Name"];
599 data.GroupPicture = new UUID(group.Data["InsigniaID"]);
600 if (role != null)
601 {
602 data.GroupPowers = UInt64.Parse(role.Data["Powers"]);
603 data.GroupTitle = role.Data["Title"];
604 }
605 data.ListInProfile = membership.Data["ListInProfile"] == "1" ? true : false;
606 data.MaturePublish = group.Data["MaturePublish"] == "1" ? true : false;
607 data.MembershipFee = Int32.Parse(group.Data["MembershipFee"]);
608 data.OpenEnrollment = group.Data["OpenEnrollment"] == "1" ? true : false;
609 data.ShowInList = group.Data["ShowInList"] == "1" ? true : false;
610
611 return data;
612 }
613
614 public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
615 {
616 List<GroupMembershipData> memberships = new List<GroupMembershipData>();
617
618 // 1. Get all the groups that this person is a member of
619 MembershipData[] mdata = m_Database.RetrieveMemberships(AgentID);
620
621 if (mdata == null || (mdata != null && mdata.Length == 0))
622 return memberships;
623
624 foreach (MembershipData d in mdata)
625 {
626 GroupMembershipData gmember = GetAgentGroupMembership(RequestingAgentID, AgentID, d.GroupID, d);
627 if (gmember != null)
628 {
629 memberships.Add(gmember);
630 //m_log.DebugFormat("[XXX]: Member of {0} as {1}", gmember.GroupName, gmember.GroupTitle);
631 //Util.PrintCallStack();
632 }
633 }
634
635 return memberships;
636 }
637
638 public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
639 {
640 MembershipData data = m_Database.RetrieveMember(GroupID, AgentID);
641 if (data == null)
642 return;
643
644 data.Data["SelectedRoleID"] = RoleID.ToString();
645 m_Database.StoreMember(data);
646 }
647
648 public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
649 {
650 // TODO: check perms
651
652 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
653 if (membership == null)
654 return;
655
656 membership.Data["AcceptNotices"] = AcceptNotices ? "1" : "0";
657 membership.Data["ListInProfile"] = ListInProfile ? "1" : "0";
658
659 m_Database.StoreMember(membership);
660 }
661
662 public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
663 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
664 {
665 // Check perms
666 if (!HasPower(RequestingAgentID, groupID, GroupPowers.SendNotices))
667 {
668 m_log.DebugFormat("[Groups]: ({0}) Attempt at sending notice to group {1} denied because of lack of permission", RequestingAgentID, groupID);
669 return false;
670 }
671
672 return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID);
673 }
674
675 public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
676 {
677 NoticeData data = m_Database.RetrieveNotice(noticeID);
678
679 if (data == null)
680 return null;
681
682 return _NoticeDataToInfo(data);
683 }
684
685 public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID groupID)
686 {
687 NoticeData[] data = m_Database.RetrieveNotices(groupID);
688 List<ExtendedGroupNoticeData> infos = new List<ExtendedGroupNoticeData>();
689
690 if (data == null || (data != null && data.Length == 0))
691 return infos;
692
693 foreach (NoticeData d in data)
694 {
695 ExtendedGroupNoticeData info = _NoticeDataToData(d);
696 infos.Add(info);
697 }
698
699 return infos;
700 }
701
702 public void ResetAgentGroupChatSessions(string agentID)
703 {
704 }
705
706 public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
707 {
708 return false;
709 }
710
711 public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
712 {
713 return false;
714 }
715
716 public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
717 {
718 }
719
720 public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
721 {
722 }
723
724 #region Actions without permission checks
725
726 private void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
727 {
728 _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty);
729 }
730
731 public void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
732 {
733 // 1. Delete membership
734 m_Database.DeleteMember(GroupID, AgentID);
735
736 // 2. Remove from rolememberships
737 m_Database.DeleteMemberAllRoles(GroupID, AgentID);
738
739 // 3. if it was active group, inactivate it
740 PrincipalData principal = m_Database.RetrievePrincipal(AgentID);
741 if (principal != null && principal.ActiveGroupID == GroupID)
742 {
743 principal.ActiveGroupID = UUID.Zero;
744 m_Database.StorePrincipal(principal);
745 }
746 }
747
748 protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string accessToken)
749 {
750 // Check if it's already there
751 MembershipData data = m_Database.RetrieveMember(GroupID, AgentID);
752 if (data != null)
753 return;
754
755 // Add the membership
756 data = new MembershipData();
757 data.PrincipalID = AgentID;
758 data.GroupID = GroupID;
759 data.Data = new Dictionary<string, string>();
760 data.Data["SelectedRoleID"] = RoleID.ToString();
761 data.Data["Contribution"] = "0";
762 data.Data["ListInProfile"] = "1";
763 data.Data["AcceptNotices"] = "1";
764 data.Data["AccessToken"] = accessToken;
765
766 m_Database.StoreMember(data);
767
768 // Add principal to everyone role
769 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, UUID.Zero);
770
771 // Add principal to role, if different from everyone role
772 if (RoleID != UUID.Zero)
773 _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
774
775 // Make thit this active group
776 PrincipalData pdata = new PrincipalData();
777 pdata.PrincipalID = AgentID;
778 pdata.ActiveGroupID = GroupID;
779 m_Database.StorePrincipal(pdata);
780
781 }
782
783 private bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add)
784 {
785 RoleData data = m_Database.RetrieveRole(groupID, roleID);
786
787 if (add && data != null) // it already exists, can't create
788 {
789 m_log.DebugFormat("[Groups]: Group {0} already exists. Can't create it again", groupID);
790 return false;
791 }
792
793 if (!add && data == null) // it deosn't exist, can't update
794 {
795 m_log.DebugFormat("[Groups]: Group {0} doesn't exist. Can't update it", groupID);
796 return false;
797 }
798
799 if (add)
800 data = new RoleData();
801
802 data.GroupID = groupID;
803 data.RoleID = roleID;
804 data.Data = new Dictionary<string, string>();
805 data.Data["Name"] = name;
806 data.Data["Description"] = description;
807 data.Data["Title"] = title;
808 data.Data["Powers"] = powers.ToString();
809
810 return m_Database.StoreRole(data);
811 }
812
813 private void _RemoveGroupRole(UUID groupID, UUID roleID)
814 {
815 m_Database.DeleteRole(groupID, roleID);
816 }
817
818 private void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
819 {
820 RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
821 if (data != null)
822 return;
823
824 data = new RoleMembershipData();
825 data.GroupID = GroupID;
826 data.PrincipalID = AgentID;
827 data.RoleID = RoleID;
828 m_Database.StoreRoleMember(data);
829
830 // Make it the SelectedRoleID
831 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
832 if (membership == null)
833 {
834 m_log.DebugFormat("[Groups]: ({0}) No such member {0} in group {1}", AgentID, GroupID);
835 return;
836 }
837
838 membership.Data["SelectedRoleID"] = RoleID.ToString();
839 m_Database.StoreMember(membership);
840
841 }
842
843 private List<GroupRolesData> _GetGroupRoles(UUID groupID)
844 {
845 List<GroupRolesData> roles = new List<GroupRolesData>();
846
847 RoleData[] data = m_Database.RetrieveRoles(groupID);
848
849 if (data == null || (data != null && data.Length == 0))
850 return roles;
851
852 foreach (RoleData d in data)
853 {
854 GroupRolesData r = new GroupRolesData();
855 r.Description = d.Data["Description"];
856 r.Members = m_Database.RoleMemberCount(groupID, d.RoleID);
857 r.Name = d.Data["Name"];
858 r.Powers = UInt64.Parse(d.Data["Powers"]);
859 r.RoleID = d.RoleID;
860 r.Title = d.Data["Title"];
861
862 roles.Add(r);
863 }
864
865 return roles;
866 }
867
868 private List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup)
869 {
870 List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
871
872 RoleData[] rdata = new RoleData[0];
873 if (!isInGroup)
874 {
875 rdata = m_Database.RetrieveRoles(GroupID);
876 if (rdata == null || (rdata != null && rdata.Length == 0))
877 return rmembers;
878 }
879 List<RoleData> rlist = new List<RoleData>(rdata);
880 if (!isInGroup)
881 rlist = rlist.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
882
883 RoleMembershipData[] data = m_Database.RetrieveRolesMembers(GroupID);
884
885 if (data == null || (data != null && data.Length == 0))
886 return rmembers;
887
888 foreach (RoleMembershipData d in data)
889 {
890 if (!isInGroup)
891 {
892 RoleData rd = rlist.Find(_r => _r.RoleID == d.RoleID); // visible role
893 if (rd == null)
894 continue;
895 }
896
897 ExtendedGroupRoleMembersData r = new ExtendedGroupRoleMembersData();
898 r.MemberID = d.PrincipalID;
899 r.RoleID = d.RoleID;
900
901 rmembers.Add(r);
902 }
903
904 return rmembers;
905 }
906
907 protected bool _AddNotice(UUID groupID, UUID noticeID, string fromName, string subject, string message,
908 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
909 {
910 NoticeData data = new NoticeData();
911 data.GroupID = groupID;
912 data.NoticeID = noticeID;
913 data.Data = new Dictionary<string, string>();
914 data.Data["FromName"] = fromName;
915 data.Data["Subject"] = subject;
916 data.Data["Message"] = message;
917 data.Data["HasAttachment"] = hasAttachment ? "1" : "0";
918 if (hasAttachment)
919 {
920 data.Data["AttachmentType"] = attType.ToString();
921 data.Data["AttachmentName"] = attName;
922 data.Data["AttachmentItemID"] = attItemID.ToString();
923 data.Data["AttachmentOwnerID"] = attOwnerID;
924 }
925 data.Data["TMStamp"] = ((uint)Util.UnixTimeSinceEpoch()).ToString();
926
927 return m_Database.StoreNotice(data);
928 }
929
930 #endregion
931
932 #region structure translations
933 ExtendedGroupRecord _GroupDataToRecord(GroupData data)
934 {
935 if (data == null)
936 return null;
937
938 ExtendedGroupRecord rec = new ExtendedGroupRecord();
939 rec.AllowPublish = data.Data["AllowPublish"] == "1" ? true : false;
940 rec.Charter = data.Data["Charter"];
941 rec.FounderID = new UUID(data.Data["FounderID"]);
942 rec.GroupID = data.GroupID;
943 rec.GroupName = data.Data["Name"];
944 rec.GroupPicture = new UUID(data.Data["InsigniaID"]);
945 rec.MaturePublish = data.Data["MaturePublish"] == "1" ? true : false;
946 rec.MembershipFee = Int32.Parse(data.Data["MembershipFee"]);
947 rec.OpenEnrollment = data.Data["OpenEnrollment"] == "1" ? true : false;
948 rec.OwnerRoleID = new UUID(data.Data["OwnerRoleID"]);
949 rec.ShowInList = data.Data["ShowInList"] == "1" ? true : false;
950 rec.ServiceLocation = data.Data["Location"];
951 rec.MemberCount = m_Database.MemberCount(data.GroupID);
952 rec.RoleCount = m_Database.RoleCount(data.GroupID);
953
954 return rec;
955 }
956
957 GroupNoticeInfo _NoticeDataToInfo(NoticeData data)
958 {
959 GroupNoticeInfo notice = new GroupNoticeInfo();
960 notice.GroupID = data.GroupID;
961 notice.Message = data.Data["Message"];
962 notice.noticeData = _NoticeDataToData(data);
963
964 return notice;
965 }
966
967 ExtendedGroupNoticeData _NoticeDataToData(NoticeData data)
968 {
969 ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData();
970 notice.FromName = data.Data["FromName"];
971 notice.NoticeID = data.NoticeID;
972 notice.Subject = data.Data["Subject"];
973 notice.Timestamp = uint.Parse((string)data.Data["TMStamp"]);
974 notice.HasAttachment = data.Data["HasAttachment"] == "1" ? true : false;
975 if (notice.HasAttachment)
976 {
977 notice.AttachmentName = data.Data["AttachmentName"];
978 notice.AttachmentItemID = new UUID(data.Data["AttachmentItemID"].ToString());
979 notice.AttachmentType = byte.Parse(data.Data["AttachmentType"].ToString());
980 notice.AttachmentOwnerID = data.Data["AttachmentOwnerID"].ToString();
981 }
982
983
984 return notice;
985 }
986
987 #endregion
988
989 #region permissions
990 private bool HasPower(string agentID, UUID groupID, GroupPowers power)
991 {
992 RoleMembershipData[] rmembership = m_Database.RetrieveMemberRoles(groupID, agentID);
993 if (rmembership == null || (rmembership != null && rmembership.Length == 0))
994 return false;
995
996 foreach (RoleMembershipData rdata in rmembership)
997 {
998 RoleData role = m_Database.RetrieveRole(groupID, rdata.RoleID);
999 if ( (UInt64.Parse(role.Data["Powers"]) & (ulong)power) != 0 )
1000 return true;
1001 }
1002 return false;
1003 }
1004
1005 private bool IsOwner(string agentID, UUID groupID)
1006 {
1007 GroupData group = m_Database.RetrieveGroup(groupID);
1008 if (group == null)
1009 return false;
1010
1011 RoleMembershipData rmembership = m_Database.RetrieveRoleMember(groupID, new UUID(group.Data["OwnerRoleID"]), agentID);
1012 if (rmembership == null)
1013 return false;
1014
1015 return true;
1016 }
1017 #endregion
1018
1019 }
1020}
diff --git a/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs
new file mode 100644
index 0000000..2611a3d
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs
@@ -0,0 +1,84 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.Groups
37{
38 public class GroupsServiceBase : ServiceBase
39 {
40 protected IGroupsData m_Database = null;
41
42 public GroupsServiceBase(IConfigSource config, string cName)
43 : base(config)
44 {
45 string dllName = String.Empty;
46 string connString = String.Empty;
47 string realm = "os_groups";
48 string configName = (cName == string.Empty) ? "Groups" : cName;
49
50 //
51 // Try reading the [DatabaseService] section, if it exists
52 //
53 IConfig dbConfig = config.Configs["DatabaseService"];
54 if (dbConfig != null)
55 {
56 if (dllName == String.Empty)
57 dllName = dbConfig.GetString("StorageProvider", String.Empty);
58 if (connString == String.Empty)
59 connString = dbConfig.GetString("ConnectionString", String.Empty);
60 }
61
62 //
63 // [Groups] section overrides [DatabaseService], if it exists
64 //
65 IConfig groupsConfig = config.Configs[configName];
66 if (groupsConfig != null)
67 {
68 dllName = groupsConfig.GetString("StorageProvider", dllName);
69 connString = groupsConfig.GetString("ConnectionString", connString);
70 realm = groupsConfig.GetString("Realm", realm);
71 }
72
73 //
74 // We tried, but this doesn't exist. We can't proceed.
75 //
76 if (dllName.Equals(String.Empty))
77 throw new Exception("No StorageProvider configured");
78
79 m_Database = LoadPlugin<IGroupsData>(dllName, new Object[] { connString, realm });
80 if (m_Database == null)
81 throw new Exception("Could not find a storage interface in the given module " + dllName);
82 }
83 }
84} \ No newline at end of file
diff --git a/OpenSim/Addons/Groups/Service/HGGroupsService.cs b/OpenSim/Addons/Groups/Service/HGGroupsService.cs
new file mode 100644
index 0000000..9d7961c
--- /dev/null
+++ b/OpenSim/Addons/Groups/Service/HGGroupsService.cs
@@ -0,0 +1,353 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using Nini.Config;
34
35using OpenMetaverse;
36using OpenSim.Data;
37using OpenSim.Framework;
38using OpenSim.Services.Interfaces;
39
40namespace OpenSim.Groups
41{
42 public class HGGroupsService : GroupsService
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private IOfflineIMService m_OfflineIM;
47 private IUserAccountService m_UserAccounts;
48 private string m_HomeURI;
49
50 public HGGroupsService(IConfigSource config, IOfflineIMService im, IUserAccountService users, string homeURI)
51 : base(config, string.Empty)
52 {
53 m_OfflineIM = im;
54 m_UserAccounts = users;
55 m_HomeURI = homeURI;
56 if (!m_HomeURI.EndsWith("/"))
57 m_HomeURI += "/";
58 }
59
60
61 #region HG specific operations
62
63 public bool CreateGroupProxy(string RequestingAgentID, string agentID, string accessToken, UUID groupID, string serviceLocation, string name, out string reason)
64 {
65 reason = string.Empty;
66 Uri uri = null;
67 try
68 {
69 uri = new Uri(serviceLocation);
70 }
71 catch (UriFormatException)
72 {
73 reason = "Bad location for group proxy";
74 return false;
75 }
76
77 // Check if it already exists
78 GroupData grec = m_Database.RetrieveGroup(groupID);
79 if (grec == null ||
80 (grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower()))
81 {
82 // Create the group
83 grec = new GroupData();
84 grec.GroupID = groupID;
85 grec.Data = new Dictionary<string, string>();
86 grec.Data["Name"] = name + " @ " + uri.Authority;
87 grec.Data["Location"] = serviceLocation;
88 grec.Data["Charter"] = string.Empty;
89 grec.Data["InsigniaID"] = UUID.Zero.ToString();
90 grec.Data["FounderID"] = UUID.Zero.ToString();
91 grec.Data["MembershipFee"] = "0";
92 grec.Data["OpenEnrollment"] = "0";
93 grec.Data["ShowInList"] = "0";
94 grec.Data["AllowPublish"] = "0";
95 grec.Data["MaturePublish"] = "0";
96 grec.Data["OwnerRoleID"] = UUID.Zero.ToString();
97
98
99 if (!m_Database.StoreGroup(grec))
100 return false;
101 }
102
103 if (grec.Data["Location"] == string.Empty)
104 {
105 reason = "Cannot add proxy membership to non-proxy group";
106 return false;
107 }
108
109 UUID uid = UUID.Zero;
110 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
111 Util.ParseUniversalUserIdentifier(RequestingAgentID, out uid, out url, out first, out last, out tmp);
112 string fromName = first + "." + last + "@" + url;
113
114 // Invite to group again
115 InviteToGroup(fromName, groupID, new UUID(agentID), grec.Data["Name"]);
116
117 // Stick the proxy membership in the DB already
118 // we'll delete it if the agent declines the invitation
119 MembershipData membership = new MembershipData();
120 membership.PrincipalID = agentID;
121 membership.GroupID = groupID;
122 membership.Data = new Dictionary<string, string>();
123 membership.Data["SelectedRoleID"] = UUID.Zero.ToString();
124 membership.Data["Contribution"] = "0";
125 membership.Data["ListInProfile"] = "1";
126 membership.Data["AcceptNotices"] = "1";
127 membership.Data["AccessToken"] = accessToken;
128
129 m_Database.StoreMember(membership);
130
131 return true;
132 }
133
134 public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, string token)
135 {
136 // check the token
137 MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
138 if (membership != null)
139 {
140 if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
141 RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
142 else
143 m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
144 }
145 else
146 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", AgentID);
147 }
148
149 public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string groupName, string token)
150 {
151 // check the token
152 if (!VerifyToken(GroupID, RequestingAgentID, token))
153 return null;
154
155 ExtendedGroupRecord grec;
156 if (GroupID == UUID.Zero)
157 grec = GetGroupRecord(RequestingAgentID, groupName);
158 else
159 grec = GetGroupRecord(RequestingAgentID, GroupID);
160
161 if (grec != null)
162 FillFounderUUI(grec);
163
164 return grec;
165 }
166
167 public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
168 {
169 if (!VerifyToken(GroupID, RequestingAgentID, token))
170 return new List<ExtendedGroupMembersData>();
171
172 List<ExtendedGroupMembersData> members = GetGroupMembers(RequestingAgentID, GroupID);
173
174 // convert UUIDs to UUIs
175 members.ForEach(delegate (ExtendedGroupMembersData m)
176 {
177 if (m.AgentID.ToString().Length == 36) // UUID
178 {
179 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.AgentID));
180 if (account != null)
181 m.AgentID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
182 }
183 });
184
185 return members;
186 }
187
188 public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
189 {
190 if (!VerifyToken(GroupID, RequestingAgentID, token))
191 return new List<GroupRolesData>();
192
193 return GetGroupRoles(RequestingAgentID, GroupID);
194 }
195
196 public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
197 {
198 if (!VerifyToken(GroupID, RequestingAgentID, token))
199 return new List<ExtendedGroupRoleMembersData>();
200
201 List<ExtendedGroupRoleMembersData> rolemembers = GetGroupRoleMembers(RequestingAgentID, GroupID);
202
203 // convert UUIDs to UUIs
204 rolemembers.ForEach(delegate(ExtendedGroupRoleMembersData m)
205 {
206 if (m.MemberID.ToString().Length == 36) // UUID
207 {
208 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.MemberID));
209 if (account != null)
210 m.MemberID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
211 }
212 });
213
214 return rolemembers;
215 }
216
217 public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
218 bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
219 {
220 // check that the group proxy exists
221 ExtendedGroupRecord grec = GetGroupRecord(RequestingAgentID, groupID);
222 if (grec == null)
223 {
224 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to non-existent group proxy");
225 return false;
226 }
227
228 // check that the group is remote
229 if (grec.ServiceLocation == string.Empty)
230 {
231 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to local (non-proxy) group");
232 return false;
233 }
234
235 // check that there isn't already a notice with the same ID
236 if (GetGroupNotice(RequestingAgentID, noticeID) != null)
237 {
238 m_log.DebugFormat("[Groups.HGGroupsService]: a notice with the same ID already exists", grec.ServiceLocation);
239 return false;
240 }
241
242 // This has good intentions (security) but it will potentially DDS the origin...
243 // We'll need to send a proof along with the message. Maybe encrypt the message
244 // using key pairs
245 //
246 //// check that the notice actually exists in the origin
247 //GroupsServiceHGConnector c = new GroupsServiceHGConnector(grec.ServiceLocation);
248 //if (!c.VerifyNotice(noticeID, groupID))
249 //{
250 // m_log.DebugFormat("[Groups.HGGroupsService]: notice does not exist at origin {0}", grec.ServiceLocation);
251 // return false;
252 //}
253
254 // ok, we're good!
255 return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID);
256 }
257
258 public bool VerifyNotice(UUID noticeID, UUID groupID)
259 {
260 GroupNoticeInfo notice = GetGroupNotice(string.Empty, noticeID);
261
262 if (notice == null)
263 return false;
264
265 if (notice.GroupID != groupID)
266 return false;
267
268 return true;
269 }
270
271 #endregion
272
273 private void InviteToGroup(string fromName, UUID groupID, UUID invitedAgentID, string groupName)
274 {
275 // Todo: Security check, probably also want to send some kind of notification
276 UUID InviteID = UUID.Random();
277
278 if (AddAgentToGroupInvite(InviteID, groupID, invitedAgentID.ToString()))
279 {
280 Guid inviteUUID = InviteID.Guid;
281
282 GridInstantMessage msg = new GridInstantMessage();
283
284 msg.imSessionID = inviteUUID;
285
286 // msg.fromAgentID = agentID.Guid;
287 msg.fromAgentID = groupID.Guid;
288 msg.toAgentID = invitedAgentID.Guid;
289 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
290 msg.timestamp = 0;
291 msg.fromAgentName = fromName;
292 msg.message = string.Format("Please confirm your acceptance to join group {0}.", groupName);
293 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
294 msg.fromGroup = true;
295 msg.offline = (byte)0;
296 msg.ParentEstateID = 0;
297 msg.Position = Vector3.Zero;
298 msg.RegionID = UUID.Zero.Guid;
299 msg.binaryBucket = new byte[20];
300
301 string reason = string.Empty;
302 m_OfflineIM.StoreMessage(msg, out reason);
303
304 }
305 }
306
307 private bool AddAgentToGroupInvite(UUID inviteID, UUID groupID, string agentID)
308 {
309 // Check whether the invitee is already a member of the group
310 MembershipData m = m_Database.RetrieveMember(groupID, agentID);
311 if (m != null)
312 return false;
313
314 // Check whether there are pending invitations and delete them
315 InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID);
316 if (invite != null)
317 m_Database.DeleteInvite(invite.InviteID);
318
319 invite = new InvitationData();
320 invite.InviteID = inviteID;
321 invite.PrincipalID = agentID;
322 invite.GroupID = groupID;
323 invite.RoleID = UUID.Zero;
324 invite.Data = new Dictionary<string, string>();
325
326 return m_Database.StoreInvitation(invite);
327 }
328
329 private void FillFounderUUI(ExtendedGroupRecord grec)
330 {
331 UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, grec.FounderID);
332 if (account != null)
333 grec.FounderUUI = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
334 }
335
336 private bool VerifyToken(UUID groupID, string agentID, string token)
337 {
338 // check the token
339 MembershipData membership = m_Database.RetrieveMember(groupID, agentID);
340 if (membership != null)
341 {
342 if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
343 return true;
344 else
345 m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
346 }
347 else
348 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", agentID);
349
350 return false;
351 }
352 }
353}
diff --git a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs
new file mode 100644
index 0000000..050ebd2
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.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 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.Reflection;
30using log4net;
31using Mono.Addins;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Client;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40
41namespace OpenSim.OfflineIM
42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")]
44 public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private bool m_Enabled = false;
49 private List<Scene> m_SceneList = new List<Scene>();
50 IMessageTransferModule m_TransferModule = null;
51 private bool m_ForwardOfflineGroupMessages = true;
52
53 private IOfflineIMService m_OfflineIMService;
54
55 public void Initialise(IConfigSource config)
56 {
57 IConfig cnf = config.Configs["Messaging"];
58 if (cnf == null)
59 return;
60 if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name)
61 return;
62
63 m_Enabled = true;
64
65 string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty);
66 if (serviceLocation == string.Empty)
67 m_OfflineIMService = new OfflineIMService(config);
68 else
69 m_OfflineIMService = new OfflineIMServiceRemoteConnector(serviceLocation);
70
71 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages);
72 m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name);
73 }
74
75 public void AddRegion(Scene scene)
76 {
77 if (!m_Enabled)
78 return;
79
80 scene.RegisterModuleInterface<IOfflineIMService>(this);
81 m_SceneList.Add(scene);
82 scene.EventManager.OnNewClient += OnNewClient;
83 }
84
85 public void RegionLoaded(Scene scene)
86 {
87 if (!m_Enabled)
88 return;
89
90 if (m_TransferModule == null)
91 {
92 m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
93 if (m_TransferModule == null)
94 {
95 scene.EventManager.OnNewClient -= OnNewClient;
96
97 m_SceneList.Clear();
98
99 m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages");
100 }
101 m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
102 }
103 }
104
105 public void RemoveRegion(Scene scene)
106 {
107 if (!m_Enabled)
108 return;
109
110 m_SceneList.Remove(scene);
111 scene.EventManager.OnNewClient -= OnNewClient;
112 m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage;
113
114 scene.ForEachClient(delegate(IClientAPI client)
115 {
116 client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
117 client.OnMuteListRequest -= OnMuteListRequest;
118 });
119 }
120
121 public void PostInitialise()
122 {
123 }
124
125 public string Name
126 {
127 get { return "Offline Message Module V2"; }
128 }
129
130 public Type ReplaceableInterface
131 {
132 get { return null; }
133 }
134
135 public void Close()
136 {
137 m_SceneList.Clear();
138 }
139
140 private Scene FindScene(UUID agentID)
141 {
142 foreach (Scene s in m_SceneList)
143 {
144 ScenePresence presence = s.GetScenePresence(agentID);
145 if (presence != null && !presence.IsChildAgent)
146 return s;
147 }
148 return null;
149 }
150
151 private IClientAPI FindClient(UUID agentID)
152 {
153 foreach (Scene s in m_SceneList)
154 {
155 ScenePresence presence = s.GetScenePresence(agentID);
156 if (presence != null && !presence.IsChildAgent)
157 return presence.ControllingClient;
158 }
159 return null;
160 }
161
162 private void OnNewClient(IClientAPI client)
163 {
164 client.OnRetrieveInstantMessages += RetrieveInstantMessages;
165 client.OnMuteListRequest += OnMuteListRequest;
166 }
167
168 private void RetrieveInstantMessages(IClientAPI client)
169 {
170 m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId);
171
172 List<GridInstantMessage> msglist = m_OfflineIMService.GetMessages(client.AgentId);
173
174 if (msglist == null)
175 m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list.");
176
177 foreach (GridInstantMessage im in msglist)
178 {
179 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
180 // send it directly or else the item will be given twice
181 client.SendInstantMessage(im);
182 else
183 {
184 // Send through scene event manager so all modules get a chance
185 // to look at this message before it gets delivered.
186 //
187 // Needed for proper state management for stored group
188 // invitations
189 //
190 Scene s = FindScene(client.AgentId);
191 if (s != null)
192 s.EventManager.TriggerIncomingInstantMessage(im);
193 }
194 }
195 }
196
197 // Apparently this is needed in order for the viewer to request the IMs.
198 private void OnMuteListRequest(IClientAPI client, uint crc)
199 {
200 m_log.DebugFormat("[OfflineIM.V2] Got mute list request for crc {0}", crc);
201 string filename = "mutes" + client.AgentId.ToString();
202
203 IXfer xfer = client.Scene.RequestModuleInterface<IXfer>();
204 if (xfer != null)
205 {
206 xfer.AddNewFile(filename, new Byte[0]);
207 client.SendMuteListUpdate(filename);
208 }
209 }
210
211 private void UndeliveredMessage(GridInstantMessage im)
212 {
213 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
214 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
215 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
216 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
217 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
218 {
219 return;
220 }
221
222 if (!m_ForwardOfflineGroupMessages)
223 {
224 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
225 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
226 return;
227 }
228
229 Scene scene = FindScene(new UUID(im.fromAgentID));
230 if (scene == null)
231 scene = m_SceneList[0];
232
233 string reason = string.Empty;
234 bool success = m_OfflineIMService.StoreMessage(im, out reason);
235
236 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
237 {
238 IClientAPI client = FindClient(new UUID(im.fromAgentID));
239 if (client == null)
240 return;
241
242 client.SendInstantMessage(new GridInstantMessage(
243 null, new UUID(im.toAgentID),
244 "System", new UUID(im.fromAgentID),
245 (byte)InstantMessageDialog.MessageFromAgent,
246 "User is not logged in. " +
247 (success ? "Message saved." : "Message not saved: " + reason),
248 false, new Vector3()));
249 }
250 }
251
252 #region IOfflineIM
253
254 public List<GridInstantMessage> GetMessages(UUID principalID)
255 {
256 return m_OfflineIMService.GetMessages(principalID);
257 }
258
259 public bool StoreMessage(GridInstantMessage im, out string reason)
260 {
261 return m_OfflineIMService.StoreMessage(im, out reason);
262 }
263
264 #endregion
265 }
266}
267
diff --git a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ffe8a3e
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")]
14[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.7.6.*")]
34
35[assembly: Addin("OpenSim.OfflineIM", "0.1")]
36[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
new file mode 100644
index 0000000..69feb76
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
@@ -0,0 +1,143 @@
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;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36using OpenSim.Services.Interfaces;
37
38using OpenMetaverse;
39using log4net;
40using Nini.Config;
41
42namespace OpenSim.OfflineIM
43{
44 public class OfflineIMServiceRemoteConnector : IOfflineIMService
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private string m_ServerURI = string.Empty;
49 private object m_Lock = new object();
50
51 public OfflineIMServiceRemoteConnector(string url)
52 {
53 m_ServerURI = url;
54 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI);
55 }
56
57 public OfflineIMServiceRemoteConnector(IConfigSource config)
58 {
59 IConfig cnf = config.Configs["Messaging"];
60 if (cnf == null)
61 {
62 m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration");
63 return;
64 }
65
66 m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty);
67
68 }
69
70 #region IOfflineIMService
71 public List<GridInstantMessage> GetMessages(UUID principalID)
72 {
73 List<GridInstantMessage> ims = new List<GridInstantMessage>();
74
75 Dictionary<string, object> sendData = new Dictionary<string, object>();
76 sendData["PrincipalID"] = principalID;
77 Dictionary<string, object> ret = MakeRequest("GET", sendData);
78
79 if (ret == null)
80 return ims;
81
82 if (!ret.ContainsKey("RESULT"))
83 return ims;
84
85 if (ret["RESULT"].ToString() == "NULL")
86 return ims;
87
88 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
89 {
90 GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary<string, object>)v);
91 ims.Add(m);
92 }
93
94 return ims;
95 }
96
97 public bool StoreMessage(GridInstantMessage im, out string reason)
98 {
99 reason = string.Empty;
100 Dictionary<string, object> sendData = OfflineIMDataUtils.GridInstantMessage(im);
101
102 Dictionary<string, object> ret = MakeRequest("STORE", sendData);
103
104 if (ret == null)
105 {
106 reason = "Bad response from server";
107 return false;
108 }
109
110 string result = ret["RESULT"].ToString();
111 if (result == "NULL" || result.ToLower() == "false")
112 {
113 reason = ret["REASON"].ToString();
114 return false;
115 }
116
117 return true;
118 }
119
120 #endregion
121
122
123 #region Make Request
124
125 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
126 {
127 sendData["METHOD"] = method;
128
129 string reply = string.Empty;
130 lock (m_Lock)
131 reply = SynchronousRestFormsRequester.MakeRequest("POST",
132 m_ServerURI + "/offlineim",
133 ServerUtils.BuildQueryString(sendData));
134
135 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
136 reply);
137
138 return replyData;
139 }
140 #endregion
141
142 }
143}
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs
new file mode 100644
index 0000000..2b3a01d
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.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.Reflection;
30using System.Text;
31using System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Server.Handlers.Base;
40using log4net;
41using OpenMetaverse;
42
43namespace OpenSim.OfflineIM
44{
45 public class OfflineIMServiceRobustConnector : ServiceConnector
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private IOfflineIMService m_OfflineIMService;
50 private string m_ConfigName = "Messaging";
51
52 public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
53 base(config, server, configName)
54 {
55 if (configName != String.Empty)
56 m_ConfigName = configName;
57
58 m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName);
59
60 m_OfflineIMService = new OfflineIMService(config);
61
62 server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService));
63 }
64 }
65
66 public class OfflineIMServicePostHandler : BaseStreamHandler
67 {
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
70 private IOfflineIMService m_OfflineIMService;
71
72 public OfflineIMServicePostHandler(IOfflineIMService service) :
73 base("POST", "/offlineim")
74 {
75 m_OfflineIMService = service;
76 }
77
78 public override byte[] Handle(string path, Stream requestData,
79 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
80 {
81 StreamReader sr = new StreamReader(requestData);
82 string body = sr.ReadToEnd();
83 sr.Close();
84 body = body.Trim();
85
86 //m_log.DebugFormat("[XXX]: query String: {0}", body);
87
88 try
89 {
90 Dictionary<string, object> request =
91 ServerUtils.ParseQueryString(body);
92
93 if (!request.ContainsKey("METHOD"))
94 return FailureResult();
95
96 string method = request["METHOD"].ToString();
97 request.Remove("METHOD");
98
99 m_log.DebugFormat("[OfflineIM.V2.Handler]: {0}", method);
100 switch (method)
101 {
102 case "GET":
103 return HandleGet(request);
104 case "STORE":
105 return HandleStore(request);
106 }
107 m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method);
108 }
109 catch (Exception e)
110 {
111 m_log.DebugFormat("[OFFLINE IM HANDLER]: Exception {0}", e.StackTrace);
112 }
113
114 return FailureResult();
115 }
116
117 byte[] HandleStore(Dictionary<string, object> request)
118 {
119 Dictionary<string, object> result = new Dictionary<string, object>();
120
121 GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request);
122
123 string reason = string.Empty;
124
125 bool success = m_OfflineIMService.StoreMessage(im, out reason);
126
127 result["RESULT"] = success.ToString();
128 if (!success)
129 result["REASON"] = reason;
130
131 string xmlString = ServerUtils.BuildXmlResponse(result);
132
133 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
134 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
135 }
136
137 byte[] HandleGet(Dictionary<string, object> request)
138 {
139 Dictionary<string, object> result = new Dictionary<string, object>();
140
141 if (!request.ContainsKey("PrincipalID"))
142 NullResult(result, "Bad network data");
143 else
144 {
145 UUID principalID = new UUID(request["PrincipalID"].ToString());
146 List<GridInstantMessage> ims = m_OfflineIMService.GetMessages(principalID);
147
148 Dictionary<string, object> dict = new Dictionary<string, object>();
149 int i = 0;
150 foreach (GridInstantMessage m in ims)
151 dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m);
152
153 result["RESULT"] = dict;
154 }
155
156 string xmlString = ServerUtils.BuildXmlResponse(result);
157
158 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
159 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
160 }
161
162 #region Helpers
163
164 private void NullResult(Dictionary<string, object> result, string reason)
165 {
166 result["RESULT"] = "NULL";
167 result["REASON"] = reason;
168 }
169
170 private byte[] FailureResult()
171 {
172 return BoolResult(false);
173 }
174
175 private byte[] SuccessResult()
176 {
177 return BoolResult(true);
178 }
179
180 private byte[] BoolResult(bool value)
181 {
182 XmlDocument doc = new XmlDocument();
183
184 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
185 "", "");
186
187 doc.AppendChild(xmlnode);
188
189 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
190 "");
191
192 doc.AppendChild(rootElement);
193
194 XmlElement result = doc.CreateElement("", "RESULT", "");
195 result.AppendChild(doc.CreateTextNode(value.ToString()));
196
197 rootElement.AppendChild(result);
198
199 return DocToBytes(doc);
200 }
201
202 private byte[] DocToBytes(XmlDocument doc)
203 {
204 MemoryStream ms = new MemoryStream();
205 XmlTextWriter xw = new XmlTextWriter(ms, null);
206 xw.Formatting = Formatting.Indented;
207 doc.WriteTo(xw);
208 xw.Flush();
209
210 return ms.ToArray();
211 }
212
213 #endregion
214 }
215}
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
new file mode 100644
index 0000000..6ba022c
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
@@ -0,0 +1,131 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Runtime.Serialization;
33using System.Text;
34using System.Timers;
35using System.Xml;
36using System.Xml.Serialization;
37using log4net;
38using Nini.Config;
39
40using OpenMetaverse;
41using OpenSim.Data;
42using OpenSim.Framework;
43using OpenSim.Services.Interfaces;
44
45namespace OpenSim.OfflineIM
46{
47 public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private const int MAX_IM = 25;
51
52 private XmlSerializer m_serializer;
53 private static bool m_Initialized = false;
54
55 public OfflineIMService(IConfigSource config)
56 : base(config)
57 {
58 m_serializer = new XmlSerializer(typeof(GridInstantMessage));
59 if (!m_Initialized)
60 {
61 m_Database.DeleteOld();
62 m_Initialized = true;
63 }
64 }
65
66 public List<GridInstantMessage> GetMessages(UUID principalID)
67 {
68 List<GridInstantMessage> ims = new List<GridInstantMessage>();
69
70 OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString());
71
72 if (messages == null || (messages != null && messages.Length == 0))
73 return ims;
74
75 foreach (OfflineIMData m in messages)
76 {
77 using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"])))
78 {
79 GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream);
80 ims.Add(im);
81 }
82 }
83
84 // Then, delete them
85 m_Database.Delete("PrincipalID", principalID.ToString());
86
87 return ims;
88 }
89
90 public bool StoreMessage(GridInstantMessage im, out string reason)
91 {
92 reason = string.Empty;
93
94 // TODO Check limits
95 UUID principalID = new UUID(im.toAgentID);
96 long count = m_Database.GetCount("PrincipalID", principalID.ToString());
97 if (count >= MAX_IM)
98 {
99 reason = "Number of offline IMs has maxed out";
100 return false;
101 }
102
103 string imXml = string.Empty;
104 using (MemoryStream mstream = new MemoryStream())
105 {
106 XmlWriterSettings settings = new XmlWriterSettings();
107 settings.Encoding = Encoding.UTF8;
108
109 using (XmlWriter writer = XmlWriter.Create(mstream, settings))
110 {
111 m_serializer.Serialize(writer, im);
112 writer.Flush();
113
114 mstream.Position = 0;
115 using (StreamReader sreader = new StreamReader(mstream))
116 {
117 imXml = sreader.ReadToEnd();
118 }
119 }
120 }
121
122 OfflineIMData data = new OfflineIMData();
123 data.PrincipalID = principalID;
124 data.Data = new Dictionary<string, string>();
125 data.Data["Message"] = imXml;
126
127 return m_Database.Store(data);
128
129 }
130 }
131}
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
new file mode 100644
index 0000000..3376be4
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
@@ -0,0 +1,83 @@
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.Reflection;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.OfflineIM
37{
38 public class OfflineIMServiceBase : ServiceBase
39 {
40 protected IOfflineIMData m_Database = null;
41
42 public OfflineIMServiceBase(IConfigSource config)
43 : base(config)
44 {
45 string dllName = String.Empty;
46 string connString = String.Empty;
47 string realm = "im_offline";
48
49 //
50 // Try reading the [DatabaseService] section, if it exists
51 //
52 IConfig dbConfig = config.Configs["DatabaseService"];
53 if (dbConfig != null)
54 {
55 if (dllName == String.Empty)
56 dllName = dbConfig.GetString("StorageProvider", String.Empty);
57 if (connString == String.Empty)
58 connString = dbConfig.GetString("ConnectionString", String.Empty);
59 }
60
61 //
62 // [Messaging] section overrides [DatabaseService], if it exists
63 //
64 IConfig imConfig = config.Configs["Messaging"];
65 if (imConfig != null)
66 {
67 dllName = imConfig.GetString("StorageProvider", dllName);
68 connString = imConfig.GetString("ConnectionString", connString);
69 realm = imConfig.GetString("Realm", realm);
70 }
71
72 //
73 // We tried, but this doesn't exist. We can't proceed.
74 //
75 if (dllName.Equals(String.Empty))
76 throw new Exception("No StorageProvider configured");
77
78 m_Database = LoadPlugin<IOfflineIMData>(dllName, new Object[] { connString, realm });
79 if (m_Database == null)
80 throw new Exception("Could not find a storage interface in the given module " + dllName);
81 }
82 }
83}
diff --git a/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs
index 57615ea..1b6a3e1 100644
--- a/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs
+++ b/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs
@@ -60,7 +60,6 @@ using System.Runtime.InteropServices;
60// 60//
61// You can specify all the values or you can default the Build and Revision Numbers 61// You can specify all the values or you can default the Build and Revision Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63// [assembly: AssemblyVersion("0.7.5.*")] 63// [assembly: AssemblyVersion("0.7.6.*")]
64 64
65[assembly : AssemblyVersion("0.7.5.*")] 65[assembly : AssemblyVersion("0.7.6.*")]
66[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file
diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs
index 14527d9..5683a72 100644
--- a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs
+++ b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs
index 633d005..510be37 100644
--- a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs
@@ -85,16 +85,26 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController
85 if (modulesConfig == null) 85 if (modulesConfig == null)
86 modulesConfig = m_openSim.ConfigSource.Source.AddConfig("Modules"); 86 modulesConfig = m_openSim.ConfigSource.Source.AddConfig("Modules");
87 87
88 Dictionary<RuntimeAddin, IList<int>> loadedModules = new Dictionary<RuntimeAddin, IList<int>>();
89
88 // Scan modules and load all that aren't disabled 90 // Scan modules and load all that aren't disabled
89 foreach (TypeExtensionNode node in 91 foreach (TypeExtensionNode node in
90 AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) 92 AddinManager.GetExtensionNodes("/OpenSim/RegionModules"))
91 { 93 {
94 IList<int> loadedModuleData;
95
96 if (!loadedModules.ContainsKey(node.Addin))
97 loadedModules.Add(node.Addin, new List<int> { 0, 0, 0 });
98
99 loadedModuleData = loadedModules[node.Addin];
100
92 if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) 101 if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null)
93 { 102 {
94 if (CheckModuleEnabled(node, modulesConfig)) 103 if (CheckModuleEnabled(node, modulesConfig))
95 { 104 {
96 m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); 105 m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type);
97 m_sharedModules.Add(node); 106 m_sharedModules.Add(node);
107 loadedModuleData[0]++;
98 } 108 }
99 } 109 }
100 else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) 110 else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null)
@@ -103,14 +113,26 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController
103 { 113 {
104 m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); 114 m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type);
105 m_nonSharedModules.Add(node); 115 m_nonSharedModules.Add(node);
116 loadedModuleData[1]++;
106 } 117 }
107 } 118 }
108 else 119 else
109 { 120 {
110 m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); 121 m_log.WarnFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type);
122 loadedModuleData[2]++;
111 } 123 }
112 } 124 }
113 125
126 foreach (KeyValuePair<RuntimeAddin, IList<int>> loadedModuleData in loadedModules)
127 {
128 m_log.InfoFormat(
129 "[REGIONMODULES]: From plugin {0}, (version {1}), loaded {2} modules, {3} shared, {4} non-shared {5} unknown",
130 loadedModuleData.Key.Id,
131 loadedModuleData.Key.Version,
132 loadedModuleData.Value[0] + loadedModuleData.Value[1] + loadedModuleData.Value[2],
133 loadedModuleData.Value[0], loadedModuleData.Value[1], loadedModuleData.Value[2]);
134 }
135
114 // Load and init the module. We try a constructor with a port 136 // Load and init the module. We try a constructor with a port
115 // if a port was given, fall back to one without if there is 137 // if a port was given, fall back to one without if there is
116 // no port or the more specific constructor fails. 138 // no port or the more specific constructor fails.
diff --git a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs
index 8ad948c..a9d3f74 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index 49fc566..e50dac6 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -50,6 +50,7 @@ using OpenSim.Region.Framework.Scenes;
50using OpenSim.Services.Interfaces; 50using OpenSim.Services.Interfaces;
51using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; 51using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
52using GridRegion = OpenSim.Services.Interfaces.GridRegion; 52using GridRegion = OpenSim.Services.Interfaces.GridRegion;
53using PermissionMask = OpenSim.Framework.PermissionMask;
53 54
54namespace OpenSim.ApplicationPlugins.RemoteController 55namespace OpenSim.ApplicationPlugins.RemoteController
55{ 56{
@@ -140,6 +141,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
140 availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod); 141 availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod);
141 142
142 // Agent management 143 // Agent management
144 availableMethods["admin_get_agents"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcGetAgentsMethod);
143 availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod); 145 availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod);
144 146
145 // User management 147 // User management
@@ -1900,6 +1902,71 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1900 m_log.Info("[RADMIN]: Access List List Request complete"); 1902 m_log.Info("[RADMIN]: Access List List Request complete");
1901 } 1903 }
1902 1904
1905 private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
1906 {
1907 Hashtable responseData = (Hashtable)response.Value;
1908 Hashtable requestData = (Hashtable)request.Params[0];
1909
1910 bool includeChildren = false;
1911
1912 if (requestData.Contains("include_children"))
1913 bool.TryParse((string)requestData["include_children"], out includeChildren);
1914
1915 Scene scene;
1916 GetSceneFromRegionParams(requestData, responseData, out scene);
1917
1918 ArrayList xmlRpcRegions = new ArrayList();
1919 responseData["regions"] = xmlRpcRegions;
1920
1921 Hashtable xmlRpcRegion = new Hashtable();
1922 xmlRpcRegions.Add(xmlRpcRegion);
1923
1924 xmlRpcRegion["name"] = scene.Name;
1925 xmlRpcRegion["id"] = scene.RegionInfo.RegionID.ToString();
1926
1927 List<ScenePresence> agents = scene.GetScenePresences();
1928 ArrayList xmlrpcAgents = new ArrayList();
1929
1930 foreach (ScenePresence agent in agents)
1931 {
1932 if (agent.IsChildAgent && !includeChildren)
1933 continue;
1934
1935 Hashtable xmlRpcAgent = new Hashtable();
1936 xmlRpcAgent.Add("name", agent.Name);
1937 xmlRpcAgent.Add("id", agent.UUID.ToString());
1938 xmlRpcAgent.Add("type", agent.PresenceType.ToString());
1939 xmlRpcAgent.Add("current_parcel_id", agent.currentParcelUUID.ToString());
1940
1941 Vector3 pos = agent.AbsolutePosition;
1942 xmlRpcAgent.Add("pos_x", pos.X.ToString());
1943 xmlRpcAgent.Add("pos_y", pos.Y.ToString());
1944 xmlRpcAgent.Add("pos_z", pos.Z.ToString());
1945
1946 Vector3 lookAt = agent.Lookat;
1947 xmlRpcAgent.Add("lookat_x", lookAt.X.ToString());
1948 xmlRpcAgent.Add("lookat_y", lookAt.Y.ToString());
1949 xmlRpcAgent.Add("lookat_z", lookAt.Z.ToString());
1950
1951 Vector3 vel = agent.Velocity;
1952 xmlRpcAgent.Add("vel_x", vel.X.ToString());
1953 xmlRpcAgent.Add("vel_y", vel.Y.ToString());
1954 xmlRpcAgent.Add("vel_z", vel.Z.ToString());
1955
1956 xmlRpcAgent.Add("is_flying", agent.Flying.ToString());
1957 xmlRpcAgent.Add("is_sat_on_ground", agent.SitGround.ToString());
1958 xmlRpcAgent.Add("is_sat_on_object", agent.IsSatOnObject.ToString());
1959
1960 xmlrpcAgents.Add(xmlRpcAgent);
1961 }
1962
1963 m_log.DebugFormat(
1964 "[REMOTE ADMIN]: XmlRpcGetAgents found {0} agents in {1}", xmlrpcAgents.Count, scene.Name);
1965
1966 xmlRpcRegion["agents"] = xmlrpcAgents;
1967 responseData["success"] = true;
1968 }
1969
1903 private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) 1970 private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
1904 { 1971 {
1905 Hashtable responseData = (Hashtable)response.Value; 1972 Hashtable responseData = (Hashtable)response.Value;
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
deleted file mode 100644
index 10f1a6e..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
+++ /dev/null
@@ -1,1465 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Security.Cryptography;
32using System.Text;
33using System.Text.RegularExpressions;
34using System.Xml;
35using OpenSim.Framework;
36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Services.Interfaces;
39
40using OpenMetaverse;
41
42namespace OpenSim.ApplicationPlugins.Rest.Inventory
43{
44
45 /// <summary>
46 /// This class represents the current REST request. It
47 /// encapsulates the request/response state and takes care
48 /// of response generation without exposing the REST handler
49 /// to the actual mechanisms involved.
50 ///
51 /// This structure is created on entry to the Handler
52 /// method and is disposed of upon return. It is part of
53 /// the plug-in infrastructure, rather than the functionally
54 /// specific REST handler, and fundamental changes to
55 /// this should be reflected in the Rest HandlerVersion. The
56 /// object is instantiated, and may be extended by, any
57 /// given handler. See the inventory handler for an example
58 /// of this.
59 ///
60 /// If possible, the underlying request/response state is not
61 /// changed until the handler explicitly issues a Respond call.
62 /// This ensures that the request/response pair can be safely
63 /// processed by subsequent, unrelated, handlers even id the
64 /// agent handler had completed much of its processing. Think
65 /// of it as a transactional req/resp capability.
66 /// </summary>
67
68 public class RequestData
69 {
70
71 // HTTP Server interface data (Received values)
72
73 internal OSHttpRequest request = null;
74 internal OSHttpResponse response = null;
75 internal string qprefix = null;
76
77 // Request lifetime values
78 // buffer is global because it is referenced by the handler
79 // in supported of streamed requests.
80 // If a service provider wants to construct the message
81 // body explicitly it can use body to do this. The value
82 // in body is used if the buffer is still null when a response
83 // is generated.
84 // Storing information in body will suppress the return of
85 // statusBody which is only intended to report status on
86 // requests which do not themselves ordinarily generate
87 // an informational response. All of this is handled in
88 // Respond().
89
90 internal byte[] buffer = null;
91 internal string body = null;
92 internal string bodyType = "text/html";
93
94 // The encoding in effect is set to a server default. It may
95 // subsequently be overridden by a Content header. This
96 // value is established during construction and is used
97 // wherever encoding services are needed.
98
99 internal Encoding encoding = Rest.Encoding;
100
101 // These values are derived from the supplied URL. They
102 // are initialized during construction.
103
104 internal string path = null;
105 internal string method = null;
106 internal Uri uri = null;
107 internal string query = null;
108 internal string hostname = "localhost";
109 internal int port = 80;
110
111 // The path part of the URI is decomposed. pathNodes
112 // is an array of every element in the URI. Parameters
113 // is an array that contains only those nodes that
114 // are not a part of the authority prefix
115
116 private string[] pathNodes = null;
117 private string[] parameters = null;
118 private static readonly string[] EmptyPath = { String.Empty };
119
120 // The status code gets set during the course of processing
121 // and is the HTTP completion code. The status body is
122 // initialized during construction, is appended to during the
123 // course of execution, and is finalized during Respond
124 // processing.
125 //
126 // Fail processing marks the request as failed and this is
127 // then used to inhibit processing during Response processing.
128
129 internal int statusCode = 0;
130 internal string statusBody = String.Empty;
131 internal bool fail = false;
132
133 // This carries the URL to which the client should be redirected.
134 // It is set by the service provider using the Redirect call.
135
136 internal string redirectLocation = null;
137
138 // These values influence response processing. They can be set by
139 // service providers according to need. The defaults are generally
140 // good.
141
142 internal bool keepAlive = false;
143 internal bool chunked = false;
144
145 // XML related state
146
147 internal XmlWriter writer = null;
148 internal XmlReader reader = null;
149
150 // Internal working state
151
152 private StringBuilder sbuilder = new StringBuilder(1024);
153 private MemoryStream xmldata = null;
154
155 // This is used to make the response mechanism idempotent.
156
157 internal bool handled = false;
158
159 // Authentication related state
160 //
161 // Two supported authentication mechanisms are:
162 // scheme = Rest.AS_BASIC;
163 // scheme = Rest.AS_DIGEST;
164 // Presented in that order (as required by spec)
165 // A service provider can set the scheme variable to
166 // force selection of a particular authentication model
167 // (choosing from amongst those supported of course)
168 //
169
170 internal bool authenticated = false;
171 internal string scheme = Rest.Scheme;
172 internal string realm = Rest.Realm;
173 internal string domain = null;
174 internal string nonce = null;
175 internal string cnonce = null;
176 internal string qop = Rest.Qop_Auth;
177 internal string opaque = null;
178 internal string stale = null;
179 internal string algorithm = Rest.Digest_MD5;
180 internal string authParms = null;
181 internal string authPrefix = null;
182 internal string userName = String.Empty;
183 internal string userPass = String.Empty;
184
185 // Session related tables. These are only needed if QOP is set to "auth-sess"
186 // and for now at least, it is not. Session related authentication is of
187 // questionable merit in the context of REST anyway, but it is, arguably, more
188 // secure.
189
190 private static Dictionary<string,string> cntable = new Dictionary<string,string>();
191 private static Dictionary<string,string> sktable = new Dictionary<string,string>();
192
193 // This dictionary is used to keep track fo all of the parameters discovered
194 // when the authorisation header is anaylsed.
195
196 private Dictionary<string,string> authparms = new Dictionary<string,string>();
197
198 // These regular expressions are used to decipher the various header entries.
199
200 private static Regex schema = new Regex("^\\s*(?<scheme>\\w+)\\s*.*",
201 RegexOptions.Compiled | RegexOptions.IgnoreCase);
202
203 private static Regex basicParms = new Regex("^\\s*(?:\\w+)\\s+(?<pval>\\S+)\\s*",
204 RegexOptions.Compiled | RegexOptions.IgnoreCase);
205
206 private static Regex digestParm1 = new Regex("\\s*(?<parm>\\w+)\\s*=\\s*\"(?<pval>[^\"]+)\"",
207 RegexOptions.Compiled | RegexOptions.IgnoreCase);
208
209 private static Regex digestParm2 = new Regex("\\s*(?<parm>\\w+)\\s*=\\s*(?<pval>[^\\p{P}\\s]+)",
210 RegexOptions.Compiled | RegexOptions.IgnoreCase);
211
212 private static Regex reuserPass = new Regex("(?<user>[^:]+):(?<pass>[\\S\\s]*)",
213 RegexOptions.Compiled | RegexOptions.IgnoreCase);
214
215 // For efficiency, we create static instances of these objects
216
217 private static MD5 md5hash = MD5.Create();
218
219 private static StringComparer sc = StringComparer.OrdinalIgnoreCase;
220
221#region properties
222
223 // Just for convenience...
224
225 internal string MsgId
226 {
227 get { return Rest.MsgId; }
228 }
229
230 /// <summary>
231 /// Return a boolean indication of whether or no an authenticated user is
232 /// associated with this request. This could be wholly integrated, but
233 /// that would make authentication mandatory.
234 /// </summary>
235
236 internal bool IsAuthenticated
237 {
238 get
239 {
240 if (Rest.Authenticate)
241 {
242 if (!authenticated)
243 {
244 authenticate();
245 }
246
247 return authenticated;
248 }
249 else return true;
250 }
251 }
252
253 /// <summary>
254 /// Access to all 'nodes' in the supplied URI as an
255 /// array of strings.
256 /// </summary>
257
258 internal string[] PathNodes
259 {
260 get
261 {
262 return pathNodes;
263 }
264 }
265
266 /// <summary>
267 /// Access to all non-prefix 'nodes' in the supplied URI as an
268 /// array of strings. These identify a specific resource that
269 /// is managed by the authority (the prefix).
270 /// </summary>
271
272 internal string[] Parameters
273 {
274 get
275 {
276 return parameters;
277 }
278 }
279
280#endregion properties
281
282#region constructors
283
284 // Constructor
285
286 internal RequestData(OSHttpRequest p_request, OSHttpResponse p_response, string p_qprefix)
287 {
288
289 request = p_request;
290 response = p_response;
291 qprefix = p_qprefix;
292
293 sbuilder.Length = 0;
294
295 encoding = request.ContentEncoding;
296
297 if (encoding == null)
298 {
299 encoding = Rest.Encoding;
300 }
301
302 method = request.HttpMethod.ToLower();
303 initUrl();
304
305 initParameters(p_qprefix.Length);
306
307 }
308
309#endregion constructors
310
311#region authentication_common
312
313 /// <summary>
314 /// The REST handler has requested authentication. Authentication
315 /// is considered to be with respect to the current values for
316 /// Realm, domain, etc.
317 ///
318 /// This method checks to see if the current request is already
319 /// authenticated for this domain. If it is, then it returns
320 /// true. If it is not, then it issues a challenge to the client
321 /// and responds negatively to the request.
322 ///
323 /// As soon as authentication failure is detected the method calls
324 /// DoChallenge() which terminates the request with REST exception
325 /// for unauthroized access.
326 /// </summary>
327
328 private void authenticate()
329 {
330
331 string authdata = request.Headers.Get("Authorization");
332 string reqscheme = String.Empty;
333
334 // If we don't have an authorization header, then this
335 // user is certainly not authorized. This is the typical
336 // pivot for the 1st request by a client.
337
338 if (authdata == null)
339 {
340 Rest.Log.DebugFormat("{0} Challenge reason: No authorization data", MsgId);
341 DoChallenge();
342 }
343
344 // So, we have authentication data, now we have to check to
345 // see what we got and whether or not it is valid for the
346 // current domain. To do this we need to interpret the data
347 // provided in the Authorization header. First we need to
348 // identify the scheme being used and route accordingly.
349
350 MatchCollection matches = schema.Matches(authdata);
351
352 foreach (Match m in matches)
353 {
354 Rest.Log.DebugFormat("{0} Scheme matched : {1}", MsgId, m.Groups["scheme"].Value);
355 reqscheme = m.Groups["scheme"].Value.ToLower();
356 }
357
358 // If we want a specific authentication mechanism, make sure
359 // we get it. null indicates we don't care. non-null indicates
360 // a specific scheme requirement.
361
362 if (scheme != null && scheme.ToLower() != reqscheme)
363 {
364 Rest.Log.DebugFormat("{0} Challenge reason: Requested scheme not acceptable", MsgId);
365 DoChallenge();
366 }
367
368 // In the future, these could be made into plug-ins...
369 // But for now at least we have no reason to use anything other
370 // then MD5. TLS/SSL are taken care of elsewhere.
371
372 switch (reqscheme)
373 {
374 case "digest" :
375 Rest.Log.DebugFormat("{0} Digest authentication offered", MsgId);
376 DoDigest(authdata);
377 break;
378
379 case "basic" :
380 Rest.Log.DebugFormat("{0} Basic authentication offered", MsgId);
381 DoBasic(authdata);
382 break;
383 }
384
385 // If the current header is invalid, then a challenge is still needed.
386
387 if (!authenticated)
388 {
389 Rest.Log.DebugFormat("{0} Challenge reason: Authentication failed", MsgId);
390 DoChallenge();
391 }
392
393 }
394
395 /// <summary>
396 /// Construct the necessary WWW-Authenticate headers and fail the request
397 /// with a NOT AUTHORIZED response. The parameters are the union of values
398 /// required by the supported schemes.
399 /// </summary>
400
401 private void DoChallenge()
402 {
403 Flush();
404 nonce = Rest.NonceGenerator(); // should be unique per 401 (and it is)
405 Challenge(scheme, realm, domain, nonce, opaque, stale, algorithm, qop, authParms);
406 Fail(Rest.HttpStatusCodeNotAuthorized);
407 }
408
409 /// <summary>
410 /// The Flush() call is here to support a problem encountered with the
411 /// client where an authentication rejection was lost because the rejection
412 /// may flow before the clienthas finished sending us the inbound data stream,
413 /// in which case the client responds to the socket error on out put, and
414 /// never sees the authentication challenge. The client should be fixed,
415 /// because this solution leaves the server prone to DOS attacks. A message
416 /// will be issued whenever flushing occurs. It can be enabled/disabled from
417 /// the configuration file.
418 /// </summary>
419
420 private void Flush()
421 {
422 if (Rest.FlushEnabled)
423 {
424 byte[] dbuffer = new byte[8192];
425 Rest.Log.WarnFormat("{0} REST server is flushing the inbound data stream", MsgId);
426 while (request.InputStream.Read(dbuffer,0,dbuffer.Length) != 0);
427 }
428 return;
429 }
430
431 // Indicate that authentication is required
432
433 private void Challenge(string scheme, string realm, string domain, string nonce,
434 string opaque, string stale, string alg,
435 string qop, string auth)
436 {
437
438 sbuilder.Length = 0;
439
440 // The service provider can force a particular scheme by
441 // assigning a value to scheme.
442
443 // Basic authentication is pretty simple.
444 // Just specify the realm in question.
445
446 if (scheme == null || scheme == Rest.AS_BASIC)
447 {
448
449 sbuilder.Append(Rest.AS_BASIC);
450
451 if (realm != null)
452 {
453 sbuilder.Append(" realm=");
454 sbuilder.Append(Rest.CS_DQUOTE);
455 sbuilder.Append(realm);
456 sbuilder.Append(Rest.CS_DQUOTE);
457 }
458 AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString());
459 }
460
461 sbuilder.Length = 0;
462
463 // Digest authentication takes somewhat more
464 // to express.
465
466 if (scheme == null || scheme == Rest.AS_DIGEST)
467 {
468
469 sbuilder.Append(Rest.AS_DIGEST);
470 sbuilder.Append(" ");
471
472 // Specify the effective realm. This should
473 // never be null if we are uthenticating, as it is required for all
474 // authentication schemes. It defines, in conjunction with the
475 // absolute URI information, the domain to which the authentication
476 // applies. It is an arbitrary string. I *believe* this allows an
477 // authentication to apply to disjoint resources within the same
478 // server.
479
480 if (realm != null)
481 {
482 sbuilder.Append("realm=");
483 sbuilder.Append(Rest.CS_DQUOTE);
484 sbuilder.Append(realm);
485 sbuilder.Append(Rest.CS_DQUOTE);
486 sbuilder.Append(Rest.CS_COMMA);
487 }
488
489 // Share our nonce. This is *uniquely* generated each time a 401 is
490 // returned. We do not generate a very sophisticated nonce at the
491 // moment (it's simply a base64 encoded UUID).
492
493 if (nonce != null)
494 {
495 sbuilder.Append("nonce=");
496 sbuilder.Append(Rest.CS_DQUOTE);
497 sbuilder.Append(nonce);
498 sbuilder.Append(Rest.CS_DQUOTE);
499 sbuilder.Append(Rest.CS_COMMA);
500 }
501
502 // The opaque string should be returned by the client unchanged in all
503 // subsequent requests.
504
505 if (opaque != null)
506 {
507 sbuilder.Append("opaque=");
508 sbuilder.Append(Rest.CS_DQUOTE);
509 sbuilder.Append(opaque);
510 sbuilder.Append(Rest.CS_DQUOTE);
511 sbuilder.Append(Rest.CS_COMMA);
512 }
513
514 // This flag indicates that the authentication was rejected because the
515 // included nonce was stale. The server might use timestamp information
516 // in the nonce to determine this. We do not.
517
518 if (stale != null)
519 {
520 sbuilder.Append("stale=");
521 sbuilder.Append(Rest.CS_DQUOTE);
522 sbuilder.Append(stale);
523 sbuilder.Append(Rest.CS_DQUOTE);
524 sbuilder.Append(Rest.CS_COMMA);
525 }
526
527 // Identifies the algorithm used to produce the digest and checksum.
528 // The default is MD5.
529
530 if (alg != null)
531 {
532 sbuilder.Append("algorithm=");
533 sbuilder.Append(alg);
534 sbuilder.Append(Rest.CS_COMMA);
535 }
536
537 // Theoretically QOP is optional, but it is required by a compliant
538 // with current versions of the scheme. In fact IE requires that QOP
539 // be specified and will refuse to authenticate otherwise.
540
541 if (qop != String.Empty)
542 {
543 sbuilder.Append("qop=");
544 sbuilder.Append(Rest.CS_DQUOTE);
545 sbuilder.Append(qop);
546 sbuilder.Append(Rest.CS_DQUOTE);
547 sbuilder.Append(Rest.CS_COMMA);
548 }
549
550 // This parameter allows for arbitrary extensions to the protocol.
551 // Unrecognized values should be simply ignored.
552
553 if (auth != null)
554 {
555 sbuilder.Append(auth);
556 sbuilder.Append(Rest.CS_COMMA);
557 }
558
559 // We don't know the userid that will be used
560 // so we cannot make any authentication domain
561 // assumptions. So the prefix will determine
562 // this.
563
564 sbuilder.Append("domain=");
565 sbuilder.Append(Rest.CS_DQUOTE);
566 sbuilder.Append(qprefix);
567 sbuilder.Append(Rest.CS_DQUOTE);
568
569 // Generate the authenticate header and we're basically
570 // done.
571
572 AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString());
573
574 }
575
576 }
577
578#endregion authentication_common
579
580#region authentication_basic
581
582 /// <summary>
583 /// Interpret a BASIC authorization claim. Some clients can only
584 /// understand this and also expect it to be the first one
585 /// offered. So we do.
586 /// OpenSim also needs this, as it is the only scheme that allows
587 /// authentication using the hashed passwords stored in the
588 /// user database.
589 /// </summary>
590
591 private void DoBasic(string authdata)
592 {
593
594 string response = null;
595
596 MatchCollection matches = basicParms.Matches(authdata);
597
598 // In the case of basic authentication there is
599 // only expected to be a single argument.
600
601 foreach (Match m in matches)
602 {
603 authparms.Add("response",m.Groups["pval"].Value);
604 Rest.Log.DebugFormat("{0} Parameter matched : {1} = {2}",
605 MsgId, "response", m.Groups["pval"].Value);
606 }
607
608 // Did we get a valid response?
609
610 if (authparms.TryGetValue("response", out response))
611 {
612 // Decode
613 response = Rest.Base64ToString(response);
614 Rest.Log.DebugFormat("{0} Auth response is: <{1}>", MsgId, response);
615
616 // Extract user & password
617 Match m = reuserPass.Match(response);
618 userName = m.Groups["user"].Value;
619 userPass = m.Groups["pass"].Value;
620
621 // Validate against user database
622 authenticated = Validate(userName,userPass);
623 }
624
625 }
626
627 /// <summary>
628 /// This method provides validation in support of the BASIC
629 /// authentication method. This is not normaly expected to be
630 /// used, but is included for completeness (and because I tried
631 /// it first).
632 /// </summary>
633
634 private bool Validate(string user, string pass)
635 {
636
637 Rest.Log.DebugFormat("{0} Simple User Validation", MsgId);
638
639 // Both values are required
640
641 if (user == null || pass == null)
642 return false;
643
644 // Eliminate any leading or trailing spaces
645 user = user.Trim();
646
647 return vetPassword(user, pass);
648
649 }
650
651 /// <summary>
652 /// This is used by the BASIC authentication scheme to calculate
653 /// the double hash used by OpenSim to encode user's passwords.
654 /// It returns true, if the supplied password is actually correct.
655 /// If the specified user-id is not recognized, but the password
656 /// matches the God password, then this is accepted as an admin
657 /// session.
658 /// </summary>
659
660 private bool vetPassword(string user, string pass)
661 {
662
663 int x;
664 string first;
665 string last;
666
667 // Distinguish the parts, if necessary
668
669 if ((x=user.IndexOf(Rest.C_SPACE)) != -1)
670 {
671 first = user.Substring(0,x);
672 last = user.Substring(x+1);
673 }
674 else
675 {
676 first = user;
677 last = String.Empty;
678 }
679
680 UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last);
681
682 // If we don't recognize the user id, perhaps it is god?
683 if (account == null)
684 return pass == Rest.GodKey;
685
686 return (Rest.AuthServices.Authenticate(account.PrincipalID, pass, 1) != string.Empty);
687
688 }
689
690#endregion authentication_basic
691
692#region authentication_digest
693
694 /// <summary>
695 /// This is an RFC2617 compliant HTTP MD5 Digest authentication
696 /// implementation. It has been tested with Firefox, Java HTTP client,
697 /// and Microsoft's Internet Explorer V7.
698 /// </summary>
699
700 private void DoDigest(string authdata)
701 {
702
703 string response = null;
704
705 // Find all of the values of the for x = "y"
706
707 MatchCollection matches = digestParm1.Matches(authdata);
708
709 foreach (Match m in matches)
710 {
711 authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value);
712 Rest.Log.DebugFormat("{0} String Parameter matched : {1} = {2}",
713 MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value);
714 }
715
716 // Find all of the values of the for x = y
717
718 matches = digestParm2.Matches(authdata);
719
720 foreach (Match m in matches)
721 {
722 authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value);
723 Rest.Log.DebugFormat("{0} Tokenized Parameter matched : {1} = {2}",
724 MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value);
725 }
726
727 // A response string MUST be returned, otherwise we are
728 // NOT authenticated.
729
730 Rest.Log.DebugFormat("{0} Validating authorization parameters", MsgId);
731
732 if (authparms.TryGetValue("response", out response))
733 {
734
735 string temp = null;
736
737 do
738 {
739
740 string nck = null;
741 string ncl = null;
742
743 // The userid is sent in clear text. Needed for the
744 // verification.
745
746 authparms.TryGetValue("username", out userName);
747
748 // All URI's of which this is a prefix are
749 // optimistically considered to be authenticated by the
750 // client. This is also needed to verify the response.
751
752 authparms.TryGetValue("uri", out authPrefix);
753
754 // There MUST be a nonce string present. We're not preserving any server
755 // side state and we can't validate the MD5 unless the client returns it
756 // to us, as it should.
757
758 if (!authparms.TryGetValue("nonce", out nonce) || nonce == null)
759 {
760 Rest.Log.WarnFormat("{0} Authentication failed: nonce missing", MsgId);
761 break;
762 }
763
764 // If there is an opaque string present, it had better
765 // match what we sent.
766
767 if (authparms.TryGetValue("opaque", out temp))
768 {
769 if (temp != opaque)
770 {
771 Rest.Log.WarnFormat("{0} Authentication failed: bad opaque value", MsgId);
772 break;
773 }
774 }
775
776 // If an algorithm string is present, it had better
777 // match what we sent.
778
779 if (authparms.TryGetValue("algorithm", out temp))
780 {
781 if (temp != algorithm)
782 {
783 Rest.Log.WarnFormat("{0} Authentication failed: bad algorithm value", MsgId);
784 break;
785 }
786 }
787
788 // Quality of protection considerations...
789
790 if (authparms.TryGetValue("qop", out temp))
791 {
792
793 qop = temp.ToLower(); // replace with actual value used
794
795 // if QOP was specified then
796 // these MUST be present.
797
798 if (!authparms.ContainsKey("cnonce"))
799 {
800 Rest.Log.WarnFormat("{0} Authentication failed: cnonce missing", MsgId);
801 Fail(Rest.HttpStatusCodeBadRequest);
802 break;
803 }
804
805 cnonce = authparms["cnonce"];
806
807 if (!authparms.TryGetValue("nc", out nck) || nck == null)
808 {
809 Rest.Log.WarnFormat("{0} Authentication failed: cnonce counter missing", MsgId);
810 Fail(Rest.HttpStatusCodeBadRequest);
811 break;
812 }
813
814 Rest.Log.DebugFormat("{0} Comparing nonce indices", MsgId);
815
816 if (cntable.TryGetValue(nonce, out ncl))
817 {
818 Rest.Log.DebugFormat("{0} nonce values: Verify that request({1}) > Reference({2})", MsgId, nck, ncl);
819
820 if (Rest.Hex2Int(ncl) >= Rest.Hex2Int(nck))
821 {
822 Rest.Log.WarnFormat("{0} Authentication failed: bad cnonce counter", MsgId);
823 Fail(Rest.HttpStatusCodeBadRequest);
824 break;
825 }
826 cntable[nonce] = nck;
827 }
828 else
829 {
830 lock (cntable) cntable.Add(nonce, nck);
831 }
832
833 }
834 else
835 {
836
837 qop = String.Empty;
838
839 // if QOP was not specified then
840 // these MUST NOT be present.
841 if (authparms.ContainsKey("cnonce"))
842 {
843 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce", MsgId);
844 Fail(Rest.HttpStatusCodeBadRequest);
845 break;
846 }
847 if (authparms.ContainsKey("nc"))
848 {
849 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce counter[2]", MsgId);
850 Fail(Rest.HttpStatusCodeBadRequest);
851 break;
852 }
853 }
854
855 // Validate the supplied userid/password info
856
857 authenticated = ValidateDigest(userName, nonce, cnonce, nck, authPrefix, response);
858
859 }
860 while (false);
861
862 }
863 else
864 Fail(Rest.HttpStatusCodeBadRequest);
865
866 }
867
868 /// <summary>
869 /// This mechanism is used by the digest authentication mechanism
870 /// to return the user's password. In fact, because the OpenSim
871 /// user's passwords are already hashed, and the HTTP mechanism
872 /// does not supply an open password, the hashed passwords cannot
873 /// be used unless the client has used the same salting mechanism
874 /// to has the password before using it in the authentication
875 /// algorithn. This is not inconceivable...
876 /// </summary>
877
878 private string getPassword(string user)
879 {
880
881 int x;
882 string first;
883 string last;
884
885 // Distinguish the parts, if necessary
886
887 if ((x=user.IndexOf(Rest.C_SPACE)) != -1)
888 {
889 first = user.Substring(0,x);
890 last = user.Substring(x+1);
891 }
892 else
893 {
894 first = user;
895 last = String.Empty;
896 }
897
898 UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last);
899 // If we don;t recognize the user id, perhaps it is god?
900
901 if (account == null)
902 {
903 Rest.Log.DebugFormat("{0} Administrator", MsgId);
904 return Rest.GodKey;
905 }
906 else
907 {
908 Rest.Log.DebugFormat("{0} Normal User {1}", MsgId, user);
909
910 // !!! REFACTORING PROBLEM
911 // This is what it was. It doesn't work in 0.7
912 // Nothing retrieves the password from the authentication service, there's only authentication.
913 //return udata.PasswordHash;
914 return string.Empty;
915 }
916
917 }
918
919 // Validate the request-digest
920
921 private bool ValidateDigest(string user, string nonce, string cnonce, string nck, string uri, string response)
922 {
923
924 string patt = null;
925 string payl = String.Empty;
926 string KDS = null;
927 string HA1 = null;
928 string HA2 = null;
929 string pass = getPassword(user);
930
931 // Generate H(A1)
932
933 if (algorithm == Rest.Digest_MD5Sess)
934 {
935 if (!sktable.ContainsKey(cnonce))
936 {
937 patt = String.Format("{0}:{1}:{2}:{3}:{4}", user, realm, pass, nonce, cnonce);
938 HA1 = HashToString(patt);
939 sktable.Add(cnonce, HA1);
940 }
941 else
942 {
943 HA1 = sktable[cnonce];
944 }
945 }
946 else
947 {
948 patt = String.Format("{0}:{1}:{2}", user, realm, pass);
949 HA1 = HashToString(patt);
950 }
951
952 // Generate H(A2)
953
954 if (qop == "auth-int")
955 {
956 patt = String.Format("{0}:{1}:{2}", request.HttpMethod, uri, HashToString(payl));
957 }
958 else
959 {
960 patt = String.Format("{0}:{1}", request.HttpMethod, uri);
961 }
962
963 HA2 = HashToString(patt);
964
965 // Generate Digest
966
967 if (qop != String.Empty)
968 {
969 patt = String.Format("{0}:{1}:{2}:{3}:{4}:{5}", HA1, nonce, nck, cnonce, qop, HA2);
970 }
971 else
972 {
973 patt = String.Format("{0}:{1}:{2}", HA1, nonce, HA2);
974 }
975
976 KDS = HashToString(patt);
977
978 // Compare the generated sequence with the original
979
980 return (0 == sc.Compare(KDS, response));
981
982 }
983
984 private string HashToString(string pattern)
985 {
986
987 Rest.Log.DebugFormat("{0} Generate <{1}>", MsgId, pattern);
988
989 byte[] hash = md5hash.ComputeHash(encoding.GetBytes(pattern));
990
991 sbuilder.Length = 0;
992
993 for (int i = 0; i < hash.Length; i++)
994 {
995 sbuilder.Append(hash[i].ToString("x2"));
996 }
997
998 Rest.Log.DebugFormat("{0} Hash = <{1}>", MsgId, sbuilder.ToString());
999
1000 return sbuilder.ToString();
1001
1002 }
1003
1004#endregion authentication_digest
1005
1006#region service_interface
1007
1008 /// <summary>
1009 /// Conditionally set a normal completion code. This allows a normal
1010 /// execution path to default.
1011 /// </summary>
1012
1013 internal void Complete()
1014 {
1015 if (statusCode == 0)
1016 {
1017 statusCode = Rest.HttpStatusCodeOK;
1018 }
1019 }
1020
1021 /// <summary>
1022 /// Indicate a functionally-dependent conclusion to the
1023 /// request. See Rest.cs for a list of possible values.
1024 /// </summary>
1025
1026 internal void Complete(int code)
1027 {
1028 statusCode = code;
1029 }
1030
1031 /// <summary>
1032 /// Indicate that a request should be redirected, using
1033 /// the HTTP completion codes. Permanent and temporary
1034 /// redirections may be indicated. The supplied URL is
1035 /// the new location of the resource.
1036 /// </summary>
1037
1038 internal void Redirect(string Url, bool temp)
1039 {
1040
1041 redirectLocation = Url;
1042
1043 if (temp)
1044 {
1045 statusCode = Rest.HttpStatusCodeTemporaryRedirect;
1046 }
1047 else
1048 {
1049 statusCode = Rest.HttpStatusCodePermanentRedirect;
1050 }
1051
1052 Fail(statusCode, String.Empty, true);
1053
1054 }
1055
1056 /// <summary>
1057 /// Fail for an arbitrary reason. Just a failure with
1058 /// headers. The supplied message will be returned in the
1059 /// message body.
1060 /// </summary>
1061
1062 internal void Fail(int code)
1063 {
1064 Fail(code, String.Empty, false);
1065 }
1066
1067 /// <summary>
1068 /// For the more adventurous. This failure also includes a
1069 /// specified entity to be appended to the code-related
1070 /// status string.
1071 /// </summary>
1072
1073 internal void Fail(int code, string addendum)
1074 {
1075 Fail(code, addendum, false);
1076 }
1077
1078 internal void Fail(int code, string addendum, bool reset)
1079 {
1080
1081 statusCode = code;
1082 appendStatus(String.Format("({0}) : {1}", code, Rest.HttpStatusDesc[code]));
1083
1084 // Add any final addendum to the status information
1085
1086 if (addendum != String.Empty)
1087 {
1088 appendStatus(String.Format(addendum));
1089 }
1090
1091 // Help us understand why the request is being rejected
1092
1093 if (Rest.DEBUG)
1094 {
1095 Rest.Log.DebugFormat("{0} Request Failure State Dump", MsgId);
1096 Rest.Log.DebugFormat("{0} Scheme = {1}", MsgId, scheme);
1097 Rest.Log.DebugFormat("{0} Realm = {1}", MsgId, realm);
1098 Rest.Log.DebugFormat("{0} Domain = {1}", MsgId, domain);
1099 Rest.Log.DebugFormat("{0} Nonce = {1}", MsgId, nonce);
1100 Rest.Log.DebugFormat("{0} CNonce = {1}", MsgId, cnonce);
1101 Rest.Log.DebugFormat("{0} Opaque = {1}", MsgId, opaque);
1102 Rest.Log.DebugFormat("{0} Stale = {1}", MsgId, stale);
1103 Rest.Log.DebugFormat("{0} Algorithm = {1}", MsgId, algorithm);
1104 Rest.Log.DebugFormat("{0} QOP = {1}", MsgId, qop);
1105 Rest.Log.DebugFormat("{0} AuthPrefix = {1}", MsgId, authPrefix);
1106 Rest.Log.DebugFormat("{0} UserName = {1}", MsgId, userName);
1107 Rest.Log.DebugFormat("{0} UserPass = {1}", MsgId, userPass);
1108 }
1109
1110 fail = true;
1111
1112 // Respond to the client's request, tag the response (for the
1113 // benefit of trace) to indicate the reason.
1114
1115 Respond(String.Format("Failure response: ({0}) : {1} ",
1116 code, Rest.HttpStatusDesc[code]));
1117
1118 // Finally initialize and the throw a RestException. All of the
1119 // handler's infrastructure knows that this is a "normal"
1120 // completion from a code point-of-view.
1121
1122 RestException re = new RestException(Rest.HttpStatusDesc[code]+" <"+code+">");
1123
1124 re.statusCode = code;
1125 re.statusDesc = Rest.HttpStatusDesc[code];
1126 re.httpmethod = method;
1127 re.httppath = path;
1128
1129 throw re;
1130
1131 }
1132
1133 // Reject this request
1134
1135 internal void Reject()
1136 {
1137 Fail(Rest.HttpStatusCodeNotImplemented, "request rejected (not implemented)");
1138 }
1139
1140 // This MUST be called by an agent handler before it returns
1141 // control to Handle, otherwise the request will be ignored.
1142 // This is called implciitly for the REST stream handlers and
1143 // is harmless if it is called twice.
1144
1145 internal virtual bool Respond(string reason)
1146 {
1147
1148
1149 Rest.Log.DebugFormat("{0} Respond ENTRY, handled = {1}, reason = {2}", MsgId, handled, reason);
1150
1151 // We do this to try and make multiple Respond requests harmless,
1152 // as it is sometimes convenient to isse a response without
1153 // certain knowledge that it has not previously been done.
1154
1155 if (!handled)
1156 {
1157
1158 Rest.Log.DebugFormat("{0} Generating Response", MsgId);
1159 Rest.Log.DebugFormat("{0} Method is {1}", MsgId, method);
1160
1161 // A Head request can NOT have a body! So don't waste time on
1162 // formatting if we're going to reject it anyway!
1163
1164 if (method != Rest.HEAD)
1165 {
1166
1167 Rest.Log.DebugFormat("{0} Response is not abbreviated", MsgId);
1168
1169 // If the writer is non-null then we know that an XML
1170 // data component exists. Flush and close the writer and
1171 // then convert the result to the expected buffer format
1172 // unless the request has already been failed for some
1173 // reason.
1174
1175 if (writer != null)
1176 {
1177 Rest.Log.DebugFormat("{0} XML Response handler extension ENTRY", MsgId);
1178 Rest.Log.DebugFormat("{0} XML Response exists", MsgId);
1179 writer.Flush();
1180 writer.Close();
1181 if (!fail)
1182 {
1183 buffer = xmldata.ToArray();
1184 AddHeader("Content-Type","application/xml");
1185 }
1186 xmldata.Close();
1187 Rest.Log.DebugFormat("{0} XML Response encoded", MsgId);
1188 Rest.Log.DebugFormat("{0} XML Response handler extension EXIT", MsgId);
1189 }
1190
1191 if (buffer == null && body != null)
1192 {
1193 buffer = encoding.GetBytes(body);
1194 AddHeader("Content-Type",bodyType);
1195 }
1196
1197 // OK, if the buffer contains something, regardless of how
1198 // it got there, set various response headers accordingly.
1199
1200 if (buffer != null)
1201 {
1202 Rest.Log.DebugFormat("{0} Buffer-based entity", MsgId);
1203 }
1204 else
1205 {
1206 if (statusBody != String.Empty)
1207 {
1208 statusBody += Rest.statusTail;
1209 buffer = encoding.GetBytes(statusBody);
1210 AddHeader("Content-Type","text/html");
1211 }
1212 else
1213 {
1214 statusBody = Rest.statusHead;
1215 appendStatus(String.Format(": ({0}) {1}",
1216 statusCode, Rest.HttpStatusDesc[statusCode]));
1217 statusBody += Rest.statusTail;
1218 buffer = encoding.GetBytes(statusBody);
1219 AddHeader("Content-Type","text/html");
1220 }
1221 }
1222
1223 response.ContentLength64 = buffer.Length;
1224
1225 if (response.ContentEncoding == null)
1226 response.ContentEncoding = encoding;
1227
1228 response.SendChunked = chunked;
1229 response.KeepAlive = keepAlive;
1230
1231 }
1232
1233 // Set the status code & description. If nothing has been stored,
1234 // we consider that a success.
1235
1236 if (statusCode == 0)
1237 {
1238 Complete();
1239 }
1240
1241 // Set the response code in the actual carrier
1242
1243 response.StatusCode = statusCode;
1244
1245 // For a redirect we need to set the relocation header accordingly
1246
1247 if (response.StatusCode == (int) Rest.HttpStatusCodeTemporaryRedirect ||
1248 response.StatusCode == (int) Rest.HttpStatusCodePermanentRedirect)
1249 {
1250 Rest.Log.DebugFormat("{0} Re-direct location is {1}", MsgId, redirectLocation);
1251 response.RedirectLocation = redirectLocation;
1252 }
1253
1254 // And include the status description if provided.
1255
1256 response.StatusDescription = Rest.HttpStatusDesc[response.StatusCode];
1257
1258 // Finally we send back our response.
1259
1260 // We've left the setting of handled' until the
1261 // last minute because the header settings included
1262 // above are pretty harmless. But everything from
1263 // here on down probably leaves the response
1264 // element unusable by anyone else.
1265
1266 handled = true;
1267
1268 // DumpHeaders();
1269
1270 // if (request.InputStream != null)
1271 // {
1272 // Rest.Log.DebugFormat("{0} Closing input stream", MsgId);
1273 // request.InputStream.Close();
1274 // }
1275
1276 if (buffer != null && buffer.Length != 0)
1277 {
1278 Rest.Log.DebugFormat("{0} Entity buffer, length = {1}", MsgId, buffer.Length);
1279 // Rest.Log.DebugFormat("{0} Entity buffer, length = {1} : <{2}>",
1280 // MsgId, buffer.Length, encoding.GetString(buffer));
1281 response.OutputStream.Write(buffer, 0, buffer.Length);
1282 }
1283
1284 // Closing the outputstream should complete the transmission process
1285
1286 Rest.Log.DebugFormat("{0} Sending response", MsgId);
1287 // response.OutputStream.Close();
1288 response.Send();
1289
1290 }
1291
1292 Rest.Log.DebugFormat("{0} Respond EXIT, handled = {1}, reason = {2}", MsgId, handled, reason);
1293
1294 return handled;
1295
1296 }
1297
1298 /// <summary>
1299 /// These methods allow a service provider to manipulate the
1300 /// request/response headers. The DumpHeaders method is intended
1301 /// for problem diagnosis.
1302 /// </summary>
1303
1304 internal void AddHeader(string hdr, string data)
1305 {
1306 if (Rest.DEBUG) Rest.Log.DebugFormat("{0} Adding header: <{1}: {2}>", MsgId, hdr, data);
1307 response.AddHeader(hdr, data);
1308 }
1309
1310 // internal void RemoveHeader(string hdr)
1311 // {
1312 // if (Rest.DEBUG)
1313 // {
1314 // Rest.Log.DebugFormat("{0} Removing header: <{1}>", MsgId, hdr);
1315 // if (response.Headers.Get(hdr) == null)
1316 // {
1317 // Rest.Log.DebugFormat("{0} No such header existed",
1318 // MsgId, hdr);
1319 // }
1320 // }
1321 // response.Headers.Remove(hdr);
1322 // }
1323
1324 // internal void DumpHeaders()
1325 // {
1326 // if (Rest.DEBUG)
1327 // {
1328 // for (int i=0;i<response.Headers.Count;i++)
1329 // {
1330 // Rest.Log.DebugFormat("{0} Header[{1}] : {2}", MsgId, i,
1331 // response.Headers.Get(i));
1332 // }
1333 // }
1334 // }
1335
1336 // Setup the XML writer for output
1337
1338 internal void initXmlWriter()
1339 {
1340 XmlWriterSettings settings = new XmlWriterSettings();
1341 xmldata = new MemoryStream();
1342 settings.Indent = true;
1343 settings.IndentChars = " ";
1344 settings.Encoding = encoding;
1345 settings.CloseOutput = false;
1346 settings.OmitXmlDeclaration = true;
1347 settings.ConformanceLevel = ConformanceLevel.Fragment;
1348 writer = XmlWriter.Create(xmldata, settings);
1349 }
1350
1351 internal void initXmlReader()
1352 {
1353
1354 XmlReaderSettings settings = new XmlReaderSettings();
1355
1356 settings.ConformanceLevel = ConformanceLevel.Fragment;
1357 settings.IgnoreComments = true;
1358 settings.IgnoreWhitespace = true;
1359 settings.IgnoreProcessingInstructions = true;
1360 settings.ValidationType = ValidationType.None;
1361
1362 reader = XmlReader.Create(request.InputStream,settings);
1363
1364 }
1365
1366 internal void appendStatus(string msg)
1367 {
1368 if (statusBody == String.Empty)
1369 {
1370 statusBody = String.Format(Rest.statusHead, request.HttpMethod);
1371 }
1372
1373 statusBody = String.Format("{0} {1}", statusBody, msg);
1374 }
1375
1376#endregion service_interface
1377
1378#region internal_methods
1379
1380 /// <summary>
1381 /// Helper methods for deconstructing and reconstructing
1382 /// URI path data.
1383 /// </summary>
1384
1385 private void initUrl()
1386 {
1387
1388 uri = request.Url;
1389
1390 if (query == null)
1391 {
1392 query = uri.Query;
1393 }
1394
1395 // If the path has not been previously initialized,
1396 // do so now.
1397
1398 if (path == null)
1399 {
1400 path = uri.AbsolutePath;
1401 if (path.EndsWith(Rest.UrlPathSeparator))
1402 path = path.Substring(0,path.Length-1);
1403 }
1404
1405 // If we succeeded in getting a path, perform any
1406 // additional pre-processing required.
1407
1408 if (path != null)
1409 {
1410 if (Rest.ExtendedEscape)
1411 {
1412 // Handle "+". Not a standard substitution, but
1413 // common enough...
1414 path = path.Replace(Rest.C_PLUS,Rest.C_SPACE);
1415 }
1416 pathNodes = path.Split(Rest.CA_PATHSEP);
1417 }
1418 else
1419 {
1420 pathNodes = EmptyPath;
1421 }
1422
1423 // Elimiate any %-escaped values. This is left until here
1424 // so that escaped "+' are not mistakenly replaced.
1425
1426 path = Uri.UnescapeDataString(path);
1427
1428 // Request server context info
1429
1430 hostname = uri.Host;
1431 port = uri.Port;
1432
1433 }
1434
1435 private int initParameters(int prfxlen)
1436 {
1437
1438 if (prfxlen < path.Length-1)
1439 {
1440 parameters = path.Substring(prfxlen+1).Split(Rest.CA_PATHSEP);
1441 }
1442 else
1443 {
1444 parameters = new string[0];
1445 }
1446
1447 // Generate a debug list of the decoded parameters
1448
1449 if (Rest.DEBUG && prfxlen < path.Length-1)
1450 {
1451 Rest.Log.DebugFormat("{0} URI: Parameters: {1}", MsgId, path.Substring(prfxlen));
1452 for (int i = 0; i < parameters.Length; i++)
1453 {
1454 Rest.Log.DebugFormat("{0} Parameter[{1}]: {2}", MsgId, i, parameters[i]);
1455 }
1456 }
1457
1458 return parameters.Length;
1459
1460 }
1461
1462#endregion internal_methods
1463
1464 }
1465}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml b/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml
deleted file mode 100644
index 777a2dc..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml
+++ /dev/null
@@ -1,11 +0,0 @@
1<Addin id="OpenSim.ApplicationPlugins.Rest.Inventory" version="0.1">
2 <Runtime>
3 <Import assembly="OpenSim.ApplicationPlugins.Rest.Inventory.dll"/>
4 </Runtime>
5 <Dependencies>
6 <Addin id="OpenSim" version="0.5" />
7 </Dependencies>
8 <Extension path = "/OpenSim/Startup">
9 <Plugin id="RestInventory" type="OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler" />
10 </Extension>
11</Addin>
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs
deleted file mode 100644
index 9755e73..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs
+++ /dev/null
@@ -1,551 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Text;
33using log4net;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Services.Interfaces;
38using IAvatarService = OpenSim.Services.Interfaces.IAvatarService;
39
40namespace OpenSim.ApplicationPlugins.Rest.Inventory
41{
42 public class Rest
43 {
44 internal static readonly ILog Log =
45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 internal static bool DEBUG = Log.IsDebugEnabled;
48
49 /// <summary>
50 /// Supported authentication schemes
51 /// </summary>
52
53 public const string AS_BASIC = "Basic"; // simple user/password verification
54 public const string AS_DIGEST = "Digest"; // password safe authentication
55
56 /// Supported Digest algorithms
57
58 public const string Digest_MD5 = "MD5"; // assumed default if omitted
59 public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST?
60
61 public const string Qop_Auth = "auth"; // authentication only
62 public const string Qop_Int = "auth-int"; // TODO
63
64 /// <summary>
65 /// These values have a single value for the whole
66 /// domain and lifetime of the plugin handler. We
67 /// make them static for ease of reference within
68 /// the assembly. These are initialized by the
69 /// RestHandler class during start-up.
70 /// </summary>
71
72 internal static IRestHandler Plugin = null;
73 internal static OpenSimBase main = null;
74 internal static string Prefix = null;
75 internal static IConfig Config = null;
76 internal static string GodKey = null;
77 internal static bool Authenticate = true;
78 internal static bool Secure = true;
79 internal static bool ExtendedEscape = true;
80 internal static bool DumpAsset = false;
81 internal static bool Fill = true;
82 internal static bool FlushEnabled = true;
83 internal static string Realm = "OpenSim REST";
84 internal static string Scheme = AS_BASIC;
85 internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4
86
87 /// <summary>
88 /// These are all dependent upon the Comms manager
89 /// being initialized. So they have to be properties
90 /// because the comms manager is now a module and is
91 /// not guaranteed to be there when the rest handler
92 /// initializes.
93 /// </summary>
94
95 internal static IInventoryService InventoryServices
96 {
97 get { return main.SceneManager.CurrentOrFirstScene.InventoryService; }
98 }
99
100 internal static IUserAccountService UserServices
101 {
102 get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; }
103 }
104
105 internal static IAuthenticationService AuthServices
106 {
107 get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; }
108 }
109
110 internal static IAvatarService AvatarServices
111 {
112 get { return main.SceneManager.CurrentOrFirstScene.AvatarService; }
113 }
114
115 internal static IAssetService AssetServices
116 {
117 get { return main.SceneManager.CurrentOrFirstScene.AssetService; }
118 }
119
120 /// <summary>
121 /// HTTP requires that status information be generated for PUT
122 /// and POST opertaions. This is in support of that. The
123 /// operation verb gets substituted into the first string,
124 /// and the completion code is inserted into the tail. The
125 /// strings are put here to encourage consistency.
126 /// </summary>
127
128 internal static string statusHead = "<html><body><title>{0} status</title><break>";
129 internal static string statusTail = "</body></html>";
130
131 internal static Dictionary<int,string> HttpStatusDesc;
132
133 static Rest()
134 {
135 HttpStatusDesc = new Dictionary<int,string>();
136 if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length)
137 {
138 Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match");
139 throw new Exception("HTTP Status array discrepancy");
140 }
141
142 // Repackage the data into something more tractable. The sparse
143 // nature of HTTP return codes makes an array a bad choice.
144
145 for (int i=0; i<HttpStatusCodeArray.Length; i++)
146 {
147 HttpStatusDesc.Add(HttpStatusCodeArray[i], HttpStatusDescArray[i]);
148 }
149 }
150
151 internal static int CreationDate
152 {
153 get { return (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
154 }
155
156 internal static string MsgId
157 {
158 get { return Plugin.MsgId; }
159 }
160
161 internal static string RequestId
162 {
163 get { return Plugin.RequestId; }
164 }
165
166 internal static Encoding Encoding = Util.UTF8;
167
168 /// <summary>
169 /// Version control for REST implementation. This
170 /// refers to the overall infrastructure represented
171 /// by the following classes
172 /// RequestData
173 /// RequestInventoryPlugin
174 /// Rest
175 /// It does no describe implementation classes such as
176 /// RestInventoryServices, which may morph much more
177 /// often. Such classes ARE dependent upon this however
178 /// and should check it in their Initialize method.
179 /// </summary>
180
181 public static readonly float Version = 1.0F;
182 public const string Name = "REST 1.0";
183
184 /// <summary>
185 /// Currently defined HTTP methods.
186 /// Only GET and HEAD are required to be
187 /// supported by all servers. See Respond
188 /// to see how these are handled.
189 /// </summary>
190
191 // REST AGENT 1.0 interpretations
192 public const string GET = "get"; // information retrieval - server state unchanged
193 public const string HEAD = "head"; // same as get except only the headers are returned.
194 public const string POST = "post"; // Replace the URI designated resource with the entity.
195 public const string PUT = "put"; // Add the entity to the context represented by the URI
196 public const string DELETE = "delete"; // Remove the URI designated resource from the server.
197
198 public const string OPTIONS = "options"; //
199 public const string TRACE = "trace"; //
200 public const string CONNECT = "connect"; //
201
202 // Define this in one place...
203
204 public const string UrlPathSeparator = "/";
205 public const string UrlMethodSeparator = ":";
206
207 // Redirection qualifications
208
209 public const bool PERMANENT = false;
210 public const bool TEMPORARY = true;
211
212 // Constant arrays used by String.Split
213
214 public static readonly char C_SPACE = ' ';
215 public static readonly char C_SLASH = '/';
216 public static readonly char C_PATHSEP = '/';
217 public static readonly char C_COLON = ':';
218 public static readonly char C_PLUS = '+';
219 public static readonly char C_PERIOD = '.';
220 public static readonly char C_COMMA = ',';
221 public static readonly char C_DQUOTE = '"';
222
223 public static readonly string CS_SPACE = " ";
224 public static readonly string CS_SLASH = "/";
225 public static readonly string CS_PATHSEP = "/";
226 public static readonly string CS_COLON = ":";
227 public static readonly string CS_PLUS = "+";
228 public static readonly string CS_PERIOD = ".";
229 public static readonly string CS_COMMA = ",";
230 public static readonly string CS_DQUOTE = "\"";
231
232 public static readonly char[] CA_SPACE = { C_SPACE };
233 public static readonly char[] CA_SLASH = { C_SLASH };
234 public static readonly char[] CA_PATHSEP = { C_PATHSEP };
235 public static readonly char[] CA_COLON = { C_COLON };
236 public static readonly char[] CA_PERIOD = { C_PERIOD };
237 public static readonly char[] CA_PLUS = { C_PLUS };
238 public static readonly char[] CA_COMMA = { C_COMMA };
239 public static readonly char[] CA_DQUOTE = { C_DQUOTE };
240
241 // HTTP Code Values (in value order)
242
243 public const int HttpStatusCodeContinue = 100;
244 public const int HttpStatusCodeSwitchingProtocols = 101;
245
246 public const int HttpStatusCodeOK = 200;
247 public const int HttpStatusCodeCreated = 201;
248 public const int HttpStatusCodeAccepted = 202;
249 public const int HttpStatusCodeNonAuthoritative = 203;
250 public const int HttpStatusCodeNoContent = 204;
251 public const int HttpStatusCodeResetContent = 205;
252 public const int HttpStatusCodePartialContent = 206;
253
254 public const int HttpStatusCodeMultipleChoices = 300;
255 public const int HttpStatusCodePermanentRedirect = 301;
256 public const int HttpStatusCodeFound = 302;
257 public const int HttpStatusCodeSeeOther = 303;
258 public const int HttpStatusCodeNotModified = 304;
259 public const int HttpStatusCodeUseProxy = 305;
260 public const int HttpStatusCodeReserved306 = 306;
261 public const int HttpStatusCodeTemporaryRedirect = 307;
262
263 public const int HttpStatusCodeBadRequest = 400;
264 public const int HttpStatusCodeNotAuthorized = 401;
265 public const int HttpStatusCodePaymentRequired = 402;
266 public const int HttpStatusCodeForbidden = 403;
267 public const int HttpStatusCodeNotFound = 404;
268 public const int HttpStatusCodeMethodNotAllowed = 405;
269 public const int HttpStatusCodeNotAcceptable = 406;
270 public const int HttpStatusCodeProxyAuthenticate = 407;
271 public const int HttpStatusCodeTimeOut = 408;
272 public const int HttpStatusCodeConflict = 409;
273 public const int HttpStatusCodeGone = 410;
274 public const int HttpStatusCodeLengthRequired = 411;
275 public const int HttpStatusCodePreconditionFailed = 412;
276 public const int HttpStatusCodeEntityTooLarge = 413;
277 public const int HttpStatusCodeUriTooLarge = 414;
278 public const int HttpStatusCodeUnsupportedMedia = 415;
279 public const int HttpStatusCodeRangeNotSatsified = 416;
280 public const int HttpStatusCodeExpectationFailed = 417;
281
282 public const int HttpStatusCodeServerError = 500;
283 public const int HttpStatusCodeNotImplemented = 501;
284 public const int HttpStatusCodeBadGateway = 502;
285 public const int HttpStatusCodeServiceUnavailable = 503;
286 public const int HttpStatusCodeGatewayTimeout = 504;
287 public const int HttpStatusCodeHttpVersionError = 505;
288
289 public static readonly int[] HttpStatusCodeArray = {
290 HttpStatusCodeContinue,
291 HttpStatusCodeSwitchingProtocols,
292 HttpStatusCodeOK,
293 HttpStatusCodeCreated,
294 HttpStatusCodeAccepted,
295 HttpStatusCodeNonAuthoritative,
296 HttpStatusCodeNoContent,
297 HttpStatusCodeResetContent,
298 HttpStatusCodePartialContent,
299 HttpStatusCodeMultipleChoices,
300 HttpStatusCodePermanentRedirect,
301 HttpStatusCodeFound,
302 HttpStatusCodeSeeOther,
303 HttpStatusCodeNotModified,
304 HttpStatusCodeUseProxy,
305 HttpStatusCodeReserved306,
306 HttpStatusCodeTemporaryRedirect,
307 HttpStatusCodeBadRequest,
308 HttpStatusCodeNotAuthorized,
309 HttpStatusCodePaymentRequired,
310 HttpStatusCodeForbidden,
311 HttpStatusCodeNotFound,
312 HttpStatusCodeMethodNotAllowed,
313 HttpStatusCodeNotAcceptable,
314 HttpStatusCodeProxyAuthenticate,
315 HttpStatusCodeTimeOut,
316 HttpStatusCodeConflict,
317 HttpStatusCodeGone,
318 HttpStatusCodeLengthRequired,
319 HttpStatusCodePreconditionFailed,
320 HttpStatusCodeEntityTooLarge,
321 HttpStatusCodeUriTooLarge,
322 HttpStatusCodeUnsupportedMedia,
323 HttpStatusCodeRangeNotSatsified,
324 HttpStatusCodeExpectationFailed,
325 HttpStatusCodeServerError,
326 HttpStatusCodeNotImplemented,
327 HttpStatusCodeBadGateway,
328 HttpStatusCodeServiceUnavailable,
329 HttpStatusCodeGatewayTimeout,
330 HttpStatusCodeHttpVersionError
331 };
332
333 // HTTP Status Descriptions (in status code order)
334 // This array must be kept strictly consistent with respect
335 // to the status code array above.
336
337 public static readonly string[] HttpStatusDescArray = {
338 "Continue Request",
339 "Switching Protocols",
340 "OK",
341 "CREATED",
342 "ACCEPTED",
343 "NON-AUTHORITATIVE INFORMATION",
344 "NO CONTENT",
345 "RESET CONTENT",
346 "PARTIAL CONTENT",
347 "MULTIPLE CHOICES",
348 "PERMANENT REDIRECT",
349 "FOUND",
350 "SEE OTHER",
351 "NOT MODIFIED",
352 "USE PROXY",
353 "RESERVED CODE 306",
354 "TEMPORARY REDIRECT",
355 "BAD REQUEST",
356 "NOT AUTHORIZED",
357 "PAYMENT REQUIRED",
358 "FORBIDDEN",
359 "NOT FOUND",
360 "METHOD NOT ALLOWED",
361 "NOT ACCEPTABLE",
362 "PROXY AUTHENTICATION REQUIRED",
363 "TIMEOUT",
364 "CONFLICT",
365 "GONE",
366 "LENGTH REQUIRED",
367 "PRECONDITION FAILED",
368 "ENTITY TOO LARGE",
369 "URI TOO LARGE",
370 "UNSUPPORTED MEDIA",
371 "RANGE NOT SATISFIED",
372 "EXPECTATION FAILED",
373 "SERVER ERROR",
374 "NOT IMPLEMENTED",
375 "BAD GATEWAY",
376 "SERVICE UNAVAILABLE",
377 "GATEWAY TIMEOUT",
378 "HTTP VERSION NOT SUPPORTED"
379 };
380
381 // HTTP Headers
382
383 public const string HttpHeaderAccept = "Accept";
384 public const string HttpHeaderAcceptCharset = "Accept-Charset";
385 public const string HttpHeaderAcceptEncoding = "Accept-Encoding";
386 public const string HttpHeaderAcceptLanguage = "Accept-Language";
387 public const string HttpHeaderAcceptRanges = "Accept-Ranges";
388 public const string HttpHeaderAge = "Age";
389 public const string HttpHeaderAllow = "Allow";
390 public const string HttpHeaderAuthorization = "Authorization";
391 public const string HttpHeaderCacheControl = "Cache-Control";
392 public const string HttpHeaderConnection = "Connection";
393 public const string HttpHeaderContentEncoding = "Content-Encoding";
394 public const string HttpHeaderContentLanguage = "Content-Language";
395 public const string HttpHeaderContentLength = "Content-Length";
396 public const string HttpHeaderContentLocation = "Content-Location";
397 public const string HttpHeaderContentMD5 = "Content-MD5";
398 public const string HttpHeaderContentRange = "Content-Range";
399 public const string HttpHeaderContentType = "Content-Type";
400 public const string HttpHeaderDate = "Date";
401 public const string HttpHeaderETag = "ETag";
402 public const string HttpHeaderExpect = "Expect";
403 public const string HttpHeaderExpires = "Expires";
404 public const string HttpHeaderFrom = "From";
405 public const string HttpHeaderHost = "Host";
406 public const string HttpHeaderIfMatch = "If-Match";
407 public const string HttpHeaderIfModifiedSince = "If-Modified-Since";
408 public const string HttpHeaderIfNoneMatch = "If-None-Match";
409 public const string HttpHeaderIfRange = "If-Range";
410 public const string HttpHeaderIfUnmodifiedSince = "If-Unmodified-Since";
411 public const string HttpHeaderLastModified = "Last-Modified";
412 public const string HttpHeaderLocation = "Location";
413 public const string HttpHeaderMaxForwards = "Max-Forwards";
414 public const string HttpHeaderPragma = "Pragma";
415 public const string HttpHeaderProxyAuthenticate = "Proxy-Authenticate";
416 public const string HttpHeaderProxyAuthorization = "Proxy-Authorization";
417 public const string HttpHeaderRange = "Range";
418 public const string HttpHeaderReferer = "Referer";
419 public const string HttpHeaderRetryAfter = "Retry-After";
420 public const string HttpHeaderServer = "Server";
421 public const string HttpHeaderTE = "TE";
422 public const string HttpHeaderTrailer = "Trailer";
423 public const string HttpHeaderTransferEncoding = "Transfer-Encoding";
424 public const string HttpHeaderUpgrade = "Upgrade";
425 public const string HttpHeaderUserAgent = "User-Agent";
426 public const string HttpHeaderVary = "Vary";
427 public const string HttpHeaderVia = "Via";
428 public const string HttpHeaderWarning = "Warning";
429 public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate";
430
431 /// Utility routines
432
433 public static string StringToBase64(string str)
434 {
435 try
436 {
437 byte[] encData_byte = new byte[str.Length];
438 encData_byte = Util.UTF8.GetBytes(str);
439 return Convert.ToBase64String(encData_byte);
440 }
441 catch
442 {
443 return String.Empty;
444 }
445 }
446
447 public static string Base64ToString(string str)
448 {
449 try
450 {
451 return Util.Base64ToString(str);
452 }
453 catch
454 {
455 return String.Empty;
456 }
457 }
458
459 private const string hvals = "0123456789abcdef";
460
461 public static int Hex2Int(string hex)
462 {
463 int val = 0;
464 int sum = 0;
465 string tmp = null;
466
467 if (hex != null)
468 {
469 tmp = hex.ToLower();
470 for (int i = 0; i < tmp.Length; i++)
471 {
472 val = hvals.IndexOf(tmp[i]);
473 if (val == -1)
474 break;
475 sum *= 16;
476 sum += val;
477 }
478 }
479
480 return sum;
481 }
482
483 // Nonce management
484
485 public static string NonceGenerator()
486 {
487 return StringToBase64(CreationDate + Guid.NewGuid().ToString());
488 }
489
490 // Dump the specified data stream
491
492 public static void Dump(byte[] data)
493 {
494 char[] buffer = new char[DumpLineSize];
495 int cc = 0;
496
497 for (int i = 0; i < data.Length; i++)
498 {
499 if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8"));
500
501 if (i % 4 == 0) Console.Write(" ");
502
503 Console.Write("{0}",data[i].ToString("x2"));
504
505 if (data[i] < 127 && data[i] > 31)
506 buffer[i % DumpLineSize] = (char) data[i];
507 else
508 buffer[i % DumpLineSize] = '.';
509
510 cc++;
511
512 if (i != 0 && (i + 1) % DumpLineSize == 0)
513 {
514 Console.Write(" |"+(new String(buffer))+"|");
515 cc = 0;
516 }
517 }
518
519 // Finish off any incomplete line
520
521 if (cc != 0)
522 {
523 for (int i = cc ; i < DumpLineSize; i++)
524 {
525 if (i % 4 == 0) Console.Write(" ");
526 Console.Write(" ");
527 buffer[i % DumpLineSize] = ' ';
528 }
529 Console.WriteLine(" |"+(new String(buffer))+"|");
530 }
531 else
532 {
533 Console.Write("\n");
534 }
535 }
536 }
537
538 // Local exception type
539
540 public class RestException : Exception
541 {
542 internal int statusCode;
543 internal string statusDesc;
544 internal string httpmethod;
545 internal string httppath;
546
547 public RestException(string msg) : base(msg)
548 {
549 }
550 }
551}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs
deleted file mode 100644
index 3cda984..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs
+++ /dev/null
@@ -1,860 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Xml;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Framework.Servers;
35using OpenSim.Framework.Servers.HttpServer;
36using OpenSim.Services.Interfaces;
37
38namespace OpenSim.ApplicationPlugins.Rest.Inventory
39{
40
41 public class RestAppearanceServices : IRest
42 {
43// private static readonly int PARM_USERID = 0;
44
45 // private static readonly int PARM_PATH = 1;
46
47// private bool enabled = false;
48 private string qPrefix = "appearance";
49
50 /// <summary>
51 /// The constructor makes sure that the service prefix is absolute
52 /// and the registers the service handler and the allocator.
53 /// </summary>
54
55 public RestAppearanceServices()
56 {
57 Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId);
58 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
59
60 // If a relative path was specified for the handler's domain,
61 // add the standard prefix to make it absolute, e.g. /admin
62
63 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
64 {
65 Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
66 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
67 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
68 Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
69 }
70
71 // Register interface using the absolute URI.
72
73 Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate);
74
75 // Activate if everything went OK
76
77// enabled = true;
78
79 Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId);
80 }
81
82 /// <summary>
83 /// Post-construction, pre-enabled initialization opportunity
84 /// Not currently exploited.
85 /// </summary>
86
87 public void Initialize()
88 {
89 }
90
91 /// <summary>
92 /// Called by the plug-in to halt service processing. Local processing is
93 /// disabled.
94 /// </summary>
95
96 public void Close()
97 {
98// enabled = false;
99 Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId);
100 }
101
102 /// <summary>
103 /// This property is declared locally because it is used a lot and
104 /// brevity is nice.
105 /// </summary>
106
107 internal string MsgId
108 {
109 get { return Rest.MsgId; }
110 }
111
112 #region Interface
113
114 /// <summary>
115 /// The plugin (RestHandler) calls this method to allocate the request
116 /// state carrier for a new request. It is destroyed when the request
117 /// completes. All request-instance specific state is kept here. This
118 /// is registered when this service provider is registered.
119 /// </summary>
120 /// <param name=request>Inbound HTTP request information</param>
121 /// <param name=response>Outbound HTTP request information</param>
122 /// <param name=qPrefix>REST service domain prefix</param>
123 /// <returns>A RequestData instance suitable for this service</returns>
124
125 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
126 {
127 return (RequestData) new AppearanceRequestData(request, response, prefix);
128 }
129
130 /// <summary>
131 /// This method is registered with the handler when this service provider
132 /// is initialized. It is called whenever the plug-in identifies this service
133 /// provider as the best match for a given request.
134 /// It handles all aspects of inventory REST processing, i.e. /admin/inventory
135 /// </summary>
136 /// <param name=hdata>A consolidated HTTP request work area</param>
137
138 private void DoAppearance(RequestData hdata)
139 {
140 // !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7
141
142 //AppearanceRequestData rdata = (AppearanceRequestData) hdata;
143
144 //Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId);
145
146 //// If we're disabled, do nothing.
147
148 //if (!enabled)
149 //{
150 // return;
151 //}
152
153 //// Now that we know this is a serious attempt to
154 //// access inventory data, we should find out who
155 //// is asking, and make sure they are authorized
156 //// to do so. We need to validate the caller's
157 //// identity before revealing anything about the
158 //// status quo. Authenticate throws an exception
159 //// via Fail if no identity information is present.
160 ////
161 //// With the present HTTP server we can't use the
162 //// builtin authentication mechanisms because they
163 //// would be enforced for all in-bound requests.
164 //// Instead we look at the headers ourselves and
165 //// handle authentication directly.
166
167 //try
168 //{
169 // if (!rdata.IsAuthenticated)
170 // {
171 // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
172 // }
173 //}
174 //catch (RestException e)
175 //{
176 // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
177 // {
178 // Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
179 // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
180 // }
181 // else
182 // {
183 // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
184 // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
185 // }
186 // throw (e);
187 //}
188
189 //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
190
191 //// We can only get here if we are authorized
192 ////
193 //// The requestor may have specified an UUID or
194 //// a conjoined FirstName LastName string. We'll
195 //// try both. If we fail with the first, UUID,
196 //// attempt, we try the other. As an example, the
197 //// URI for a valid inventory request might be:
198 ////
199 //// http://<host>:<port>/admin/inventory/Arthur Dent
200 ////
201 //// Indicating that this is an inventory request for
202 //// an avatar named Arthur Dent. This is ALL that is
203 //// required to designate a GET for an entire
204 //// inventory.
205 ////
206
207 //// Do we have at least a user agent name?
208
209 //if (rdata.Parameters.Length < 1)
210 //{
211 // Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId);
212 // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
213 //}
214
215 //// The first parameter MUST be the agent identification, either an UUID
216 //// or a space-separated First-name Last-Name specification. We check for
217 //// an UUID first, if anyone names their character using a valid UUID
218 //// that identifies another existing avatar will cause this a problem...
219
220 //try
221 //{
222 // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
223 // Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
224 // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
225 //}
226 //catch
227 //{
228 // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
229 // if (names.Length == 2)
230 // {
231 // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
232 // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
233 // }
234 // else
235 // {
236 // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
237 // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
238 // }
239 //}
240
241 //// If the user profile is null then either the server is broken, or the
242 //// user is not known. We always assume the latter case.
243
244 //if (rdata.userProfile != null)
245 //{
246 // Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}",
247 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
248 //}
249 //else
250 //{
251 // Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path);
252 // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
253 //}
254
255 //// If we get to here, then we have effectively validated the user's
256
257 //switch (rdata.method)
258 //{
259 // case Rest.HEAD : // Do the processing, set the status code, suppress entity
260 // DoGet(rdata);
261 // rdata.buffer = null;
262 // break;
263
264 // case Rest.GET : // Do the processing, set the status code, return entity
265 // DoGet(rdata);
266 // break;
267
268 // case Rest.PUT : // Update named element
269 // DoUpdate(rdata);
270 // break;
271
272 // case Rest.POST : // Add new information to identified context.
273 // DoExtend(rdata);
274 // break;
275
276 // case Rest.DELETE : // Delete information
277 // DoDelete(rdata);
278 // break;
279
280 // default :
281 // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
282 // MsgId, rdata.method, rdata.path);
283 // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
284 // String.Format("{0} not supported", rdata.method));
285 // break;
286 //}
287 }
288
289 #endregion Interface
290
291 #region method-specific processing
292
293 /// <summary>
294 /// This method implements GET processing for user's appearance.
295 /// </summary>
296 /// <param name=rdata>HTTP service request work area</param>
297
298// private void DoGet(AppearanceRequestData rdata)
299// {
300// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
301//
302// if (adata == null)
303// {
304// rdata.Fail(Rest.HttpStatusCodeNoContent,
305// String.Format("appearance data not found for user {0} {1}",
306// rdata.userProfile.FirstName, rdata.userProfile.SurName));
307// }
308// rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID);
309//
310// rdata.initXmlWriter();
311//
312// FormatUserAppearance(rdata);
313//
314// // Indicate a successful request
315//
316// rdata.Complete();
317//
318// // Send the response to the user. The body will be implicitly
319// // constructed from the result of the XML writer.
320//
321// rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method));
322// }
323
324 /// <summary>
325 /// POST adds NEW information to the user profile database.
326 /// This effectively resets the appearance before applying those
327 /// characteristics supplied in the request.
328 /// </summary>
329
330// private void DoExtend(AppearanceRequestData rdata)
331// {
332//
333// bool created = false;
334// bool modified = false;
335// string newnode = String.Empty;
336//
337// Rest.Log.DebugFormat("{0} POST ENTRY", MsgId);
338//
339// //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
340//
341// rdata.userAppearance = new AvatarAppearance();
342//
343// // Although the following behavior is admitted by HTTP I am becoming
344// // increasingly doubtful that it is appropriate for REST. If I attempt to
345// // add a new record, and it already exists, then it seems to me that the
346// // attempt should fail, rather than update the existing record.
347// AvatarData adata = null;
348// if (GetUserAppearance(rdata))
349// {
350// modified = rdata.userAppearance != null;
351// created = !modified;
352// adata = new AvatarData(rdata.userAppearance);
353// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
354// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
355// }
356// else
357// {
358// created = true;
359// adata = new AvatarData(rdata.userAppearance);
360// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
361// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
362// }
363//
364// if (created)
365// {
366// newnode = String.Format("{0} {1}", rdata.userProfile.FirstName,
367// rdata.userProfile.SurName);
368// // Must include a location header with a URI that identifies the new resource.
369//
370// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}",
371// rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode));
372// rdata.Complete(Rest.HttpStatusCodeCreated);
373//
374// }
375// else
376// {
377// if (modified)
378// {
379// rdata.Complete(Rest.HttpStatusCodeOK);
380// }
381// else
382// {
383// rdata.Complete(Rest.HttpStatusCodeNoContent);
384// }
385// }
386//
387// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
388//
389// }
390
391 /// <summary>
392 /// This updates the user's appearance. not all aspects need to be provided,
393 /// only those supplied will be changed.
394 /// </summary>
395
396// private void DoUpdate(AppearanceRequestData rdata)
397// {
398//
399// // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7
400//
401// //bool created = false;
402// //bool modified = false;
403//
404//
405// //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
406//
407// //// If the user exists then this is considered a modification regardless
408// //// of what may, or may not be, specified in the payload.
409//
410// //if (rdata.userAppearance != null)
411// //{
412// // modified = true;
413// // Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
414// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
415// //}
416//
417// //if (created)
418// //{
419// // rdata.Complete(Rest.HttpStatusCodeCreated);
420// //}
421// //else
422// //{
423// // if (modified)
424// // {
425// // rdata.Complete(Rest.HttpStatusCodeOK);
426// // }
427// // else
428// // {
429// // rdata.Complete(Rest.HttpStatusCodeNoContent);
430// // }
431// //}
432//
433// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
434//
435// }
436
437 /// <summary>
438 /// Delete the specified user's appearance. This actually performs a reset
439 /// to the default avatar appearance, if the info is already there.
440 /// Existing ownership is preserved. All prior updates are lost and can not
441 /// be recovered.
442 /// </summary>
443// private void DoDelete(AppearanceRequestData rdata)
444// {
445// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
446//
447// if (adata != null)
448// {
449// AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID);
450// rdata.userAppearance = new AvatarAppearance();
451// rdata.userAppearance.Owner = old.Owner;
452// adata = new AvatarData(rdata.userAppearance);
453//
454// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
455//
456// rdata.Complete();
457// }
458// else
459// {
460//
461// rdata.Complete(Rest.HttpStatusCodeNoContent);
462// }
463//
464// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
465// }
466
467#endregion method-specific processing
468
469 private bool GetUserAppearance(AppearanceRequestData rdata)
470 {
471
472 XmlReader xml;
473 bool indata = false;
474
475 rdata.initXmlReader();
476 xml = rdata.reader;
477
478 while (xml.Read())
479 {
480 switch (xml.NodeType)
481 {
482 case XmlNodeType.Element :
483 switch (xml.Name)
484 {
485 case "Appearance" :
486 if (xml.MoveToAttribute("Height"))
487 {
488 rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value);
489 indata = true;
490 }
491// if (xml.MoveToAttribute("Owner"))
492// {
493// rdata.userAppearance.Owner = (UUID)xml.Value;
494// indata = true;
495// }
496 if (xml.MoveToAttribute("Serial"))
497 {
498 rdata.userAppearance.Serial = Convert.ToInt32(xml.Value);
499 indata = true;
500 }
501 break;
502/*
503 case "Body" :
504 if (xml.MoveToAttribute("Item"))
505 {
506 rdata.userAppearance.BodyItem = (UUID)xml.Value;
507 indata = true;
508 }
509 if (xml.MoveToAttribute("Asset"))
510 {
511 rdata.userAppearance.BodyAsset = (UUID)xml.Value;
512 indata = true;
513 }
514 break;
515 case "Skin" :
516 if (xml.MoveToAttribute("Item"))
517 {
518 rdata.userAppearance.SkinItem = (UUID)xml.Value;
519 indata = true;
520 }
521 if (xml.MoveToAttribute("Asset"))
522 {
523 rdata.userAppearance.SkinAsset = (UUID)xml.Value;
524 indata = true;
525 }
526 break;
527 case "Hair" :
528 if (xml.MoveToAttribute("Item"))
529 {
530 rdata.userAppearance.HairItem = (UUID)xml.Value;
531 indata = true;
532 }
533 if (xml.MoveToAttribute("Asset"))
534 {
535 rdata.userAppearance.HairAsset = (UUID)xml.Value;
536 indata = true;
537 }
538 break;
539 case "Eyes" :
540 if (xml.MoveToAttribute("Item"))
541 {
542 rdata.userAppearance.EyesItem = (UUID)xml.Value;
543 indata = true;
544 }
545 if (xml.MoveToAttribute("Asset"))
546 {
547 rdata.userAppearance.EyesAsset = (UUID)xml.Value;
548 indata = true;
549 }
550 break;
551 case "Shirt" :
552 if (xml.MoveToAttribute("Item"))
553 {
554 rdata.userAppearance.ShirtItem = (UUID)xml.Value;
555 indata = true;
556 }
557 if (xml.MoveToAttribute("Asset"))
558 {
559 rdata.userAppearance.ShirtAsset = (UUID)xml.Value;
560 indata = true;
561 }
562 break;
563 case "Pants" :
564 if (xml.MoveToAttribute("Item"))
565 {
566 rdata.userAppearance.PantsItem = (UUID)xml.Value;
567 indata = true;
568 }
569 if (xml.MoveToAttribute("Asset"))
570 {
571 rdata.userAppearance.PantsAsset = (UUID)xml.Value;
572 indata = true;
573 }
574 break;
575 case "Shoes" :
576 if (xml.MoveToAttribute("Item"))
577 {
578 rdata.userAppearance.ShoesItem = (UUID)xml.Value;
579 indata = true;
580 }
581 if (xml.MoveToAttribute("Asset"))
582 {
583 rdata.userAppearance.ShoesAsset = (UUID)xml.Value;
584 indata = true;
585 }
586 break;
587 case "Socks" :
588 if (xml.MoveToAttribute("Item"))
589 {
590 rdata.userAppearance.SocksItem = (UUID)xml.Value;
591 indata = true;
592 }
593 if (xml.MoveToAttribute("Asset"))
594 {
595 rdata.userAppearance.SocksAsset = (UUID)xml.Value;
596 indata = true;
597 }
598 break;
599 case "Jacket" :
600 if (xml.MoveToAttribute("Item"))
601 {
602 rdata.userAppearance.JacketItem = (UUID)xml.Value;
603 indata = true;
604 }
605 if (xml.MoveToAttribute("Asset"))
606 {
607 rdata.userAppearance.JacketAsset = (UUID)xml.Value;
608 indata = true;
609 }
610 break;
611 case "Gloves" :
612 if (xml.MoveToAttribute("Item"))
613 {
614 rdata.userAppearance.GlovesItem = (UUID)xml.Value;
615 indata = true;
616 }
617 if (xml.MoveToAttribute("Asset"))
618 {
619 rdata.userAppearance.GlovesAsset = (UUID)xml.Value;
620 indata = true;
621 }
622 break;
623 case "UnderShirt" :
624 if (xml.MoveToAttribute("Item"))
625 {
626 rdata.userAppearance.UnderShirtItem = (UUID)xml.Value;
627 indata = true;
628 }
629 if (xml.MoveToAttribute("Asset"))
630 {
631 rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value;
632 indata = true;
633 }
634 break;
635 case "UnderPants" :
636 if (xml.MoveToAttribute("Item"))
637 {
638 rdata.userAppearance.UnderPantsItem = (UUID)xml.Value;
639 indata = true;
640 }
641 if (xml.MoveToAttribute("Asset"))
642 {
643 rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value;
644 indata = true;
645 }
646 break;
647 case "Skirt" :
648 if (xml.MoveToAttribute("Item"))
649 {
650 rdata.userAppearance.SkirtItem = (UUID)xml.Value;
651 indata = true;
652 }
653 if (xml.MoveToAttribute("Asset"))
654 {
655 rdata.userAppearance.SkirtAsset = (UUID)xml.Value;
656 indata = true;
657 }
658 break;
659*/
660 case "Attachment" :
661 {
662
663 int ap;
664 UUID asset;
665 UUID item;
666
667 if (xml.MoveToAttribute("AtPoint"))
668 {
669 ap = Convert.ToInt32(xml.Value);
670 if (xml.MoveToAttribute("Asset"))
671 {
672 asset = new UUID(xml.Value);
673 if (xml.MoveToAttribute("Asset"))
674 {
675 item = new UUID(xml.Value);
676 rdata.userAppearance.SetAttachment(ap, item, asset);
677 indata = true;
678 }
679 }
680 }
681 }
682 break;
683 case "Texture" :
684 if (xml.MoveToAttribute("Default"))
685 {
686 rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value));
687 indata = true;
688 }
689 break;
690 case "Face" :
691 {
692 uint index;
693 if (xml.MoveToAttribute("Index"))
694 {
695 index = Convert.ToUInt32(xml.Value);
696 if (xml.MoveToAttribute("Id"))
697 {
698 rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value);
699 indata = true;
700 }
701 }
702 }
703 break;
704 case "VisualParameters" :
705 {
706 xml.ReadContentAsBase64(rdata.userAppearance.VisualParams,
707 0, rdata.userAppearance.VisualParams.Length);
708 indata = true;
709 }
710 break;
711 }
712 break;
713 }
714 }
715
716 return indata;
717
718 }
719
720 private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset)
721 {
722 if (item != UUID.Zero || asset != UUID.Zero)
723 {
724 rdata.writer.WriteStartElement(part);
725 if (item != UUID.Zero)
726 {
727 rdata.writer.WriteAttributeString("Item",item.ToString());
728 }
729
730 if (asset != UUID.Zero)
731 {
732 rdata.writer.WriteAttributeString("Asset",asset.ToString());
733 }
734 rdata.writer.WriteEndElement();
735 }
736 }
737
738 private void FormatUserAppearance(AppearanceRequestData rdata)
739 {
740
741 Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId);
742
743 if (rdata.userAppearance != null)
744 {
745
746 Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId);
747 rdata.writer.WriteStartElement("Appearance");
748
749 rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString());
750// if (rdata.userAppearance.Owner != UUID.Zero)
751// rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString());
752 rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString());
753
754/*
755 FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset);
756 FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset);
757 FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset);
758 FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset);
759
760 FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset);
761 FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset);
762 FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset);
763 FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset);
764 FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset);
765
766 FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset);
767 FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset);
768
769 FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset);
770 FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset);
771*/
772 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId);
773
774 rdata.writer.WriteStartElement("Attachments");
775 List<AvatarAttachment> attachments = rdata.userAppearance.GetAttachments();
776 foreach (AvatarAttachment attach in attachments)
777 {
778 rdata.writer.WriteStartElement("Attachment");
779 rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString());
780 rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString());
781 rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString());
782 rdata.writer.WriteEndElement();
783 }
784 rdata.writer.WriteEndElement();
785
786 Primitive.TextureEntry texture = rdata.userAppearance.Texture;
787
788 if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null))
789 {
790 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId);
791
792 rdata.writer.WriteStartElement("Texture");
793
794 if (texture.DefaultTexture != null)
795 {
796 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId);
797 rdata.writer.WriteAttributeString("Default",
798 texture.DefaultTexture.TextureID.ToString());
799 }
800
801 if (texture.FaceTextures != null)
802 {
803
804 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId);
805
806 for (int i=0; i<texture.FaceTextures.Length;i++)
807 {
808 if (texture.FaceTextures[i] != null)
809 {
810 rdata.writer.WriteStartElement("Face");
811 rdata.writer.WriteAttributeString("Index", i.ToString());
812 rdata.writer.WriteAttributeString("Id",
813 texture.FaceTextures[i].TextureID.ToString());
814 rdata.writer.WriteEndElement();
815 }
816 }
817 }
818
819 rdata.writer.WriteEndElement();
820 }
821
822 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId);
823
824 rdata.writer.WriteStartElement("VisualParameters");
825 rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0,
826 rdata.userAppearance.VisualParams.Length);
827 rdata.writer.WriteEndElement();
828 rdata.writer.WriteFullEndElement();
829 }
830
831 Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId);
832
833 return;
834 }
835
836 #region appearance RequestData extension
837
838 internal class AppearanceRequestData : RequestData
839 {
840
841 /// <summary>
842 /// These are the inventory specific request/response state
843 /// extensions.
844 /// </summary>
845
846 internal UUID uuid = UUID.Zero;
847 internal UserProfileData userProfile = null;
848 internal AvatarAppearance userAppearance = null;
849
850 internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
851 : base(request, response, prefix)
852 {
853 }
854
855 }
856
857 #endregion Appearance RequestData extension
858
859 }
860}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
deleted file mode 100644
index 4ba3d77..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
+++ /dev/null
@@ -1,383 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Xml;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Framework.Servers;
33using OpenSim.Framework.Servers.HttpServer;
34
35namespace OpenSim.ApplicationPlugins.Rest.Inventory
36{
37 public class RestAssetServices : IRest
38 {
39 private bool enabled = false;
40 private string qPrefix = "assets";
41
42 // A simple constructor is used to handle any once-only
43 // initialization of working classes.
44
45 public RestAssetServices()
46 {
47 Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
48 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
49
50 // If the handler specifies a relative path for its domain
51 // then we must add the standard absolute prefix, e.g. /admin
52
53 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
54 {
55 Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
56 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
57 Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
58 }
59
60 // Register interface using the fully-qualified prefix
61
62 Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate);
63
64 // Activate if all went OK
65
66 enabled = true;
67
68 Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId);
69 }
70
71 // Post-construction, pre-enabled initialization opportunity
72 // Not currently exploited.
73
74 public void Initialize()
75 {
76 }
77
78 // Called by the plug-in to halt REST processing. Local processing is
79 // disabled, and control blocks until all current processing has
80 // completed. No new processing will be started
81
82 public void Close()
83 {
84 enabled = false;
85 Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix);
86 }
87
88 // Properties
89
90 internal string MsgId
91 {
92 get { return Rest.MsgId; }
93 }
94
95 #region Interface
96
97 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
98 {
99 return (RequestData) new AssetRequestData(request, response, prefix);
100 }
101
102 // Asset Handler
103
104 private void DoAsset(RequestData rparm)
105 {
106 if (!enabled) return;
107
108 AssetRequestData rdata = (AssetRequestData) rparm;
109
110 Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix);
111
112 // Now that we know this is a serious attempt to
113 // access inventory data, we should find out who
114 // is asking, and make sure they are authorized
115 // to do so. We need to validate the caller's
116 // identity before revealing anything about the
117 // status quo. Authenticate throws an exception
118 // via Fail if no identity information is present.
119 //
120 // With the present HTTP server we can't use the
121 // builtin authentication mechanisms because they
122 // would be enforced for all in-bound requests.
123 // Instead we look at the headers ourselves and
124 // handle authentication directly.
125
126 try
127 {
128 if (!rdata.IsAuthenticated)
129 {
130 rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
131 }
132 }
133 catch (RestException e)
134 {
135 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
136 {
137 Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
138 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
139 rdata.request.Headers.Get("Authorization"));
140 }
141 else
142 {
143 Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
144 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
145 rdata.request.Headers.Get("Authorization"));
146 }
147 throw (e);
148 }
149
150 // Remove the prefix and what's left are the parameters. If we don't have
151 // the parameters we need, fail the request. Parameters do NOT include
152 // any supplied query values.
153
154 if (rdata.Parameters.Length > 0)
155 {
156 switch (rdata.method)
157 {
158 case "get" :
159 DoGet(rdata);
160 break;
161 case "put" :
162 DoPut(rdata);
163 break;
164 case "post" :
165 DoPost(rdata);
166 break;
167 case "delete" :
168 default :
169 Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}",
170 MsgId, rdata.method);
171 rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
172 break;
173 }
174 }
175 else
176 {
177 Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId);
178 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
179 }
180
181 Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId);
182 }
183
184 #endregion Interface
185
186 /// <summary>
187 /// The only parameter we recognize is a UUID.If an asset with this identification is
188 /// found, it's content, base-64 encoded, is returned to the client.
189 /// </summary>
190
191 private void DoGet(AssetRequestData rdata)
192 {
193 Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
194
195 if (rdata.Parameters.Length == 1)
196 {
197 UUID uuid = new UUID(rdata.Parameters[0]);
198 AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
199
200 if (asset != null)
201 {
202 Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]);
203
204 rdata.initXmlWriter();
205
206 rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty);
207
208 rdata.writer.WriteAttributeString("id", asset.ID);
209 rdata.writer.WriteAttributeString("name", asset.Name);
210 rdata.writer.WriteAttributeString("desc", asset.Description);
211 rdata.writer.WriteAttributeString("type", asset.Type.ToString());
212 rdata.writer.WriteAttributeString("local", asset.Local.ToString());
213 rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString());
214
215 rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length);
216
217 rdata.writer.WriteFullEndElement();
218
219 }
220 else
221 {
222 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
223 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
224 }
225 }
226
227 rdata.Complete();
228 rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method));
229
230 }
231
232 /// <summary>
233 /// UPDATE existing item, if it exists. URI identifies the item in question.
234 /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
235 /// is decoded and stored in the database, identified by the supplied UUID.
236 /// </summary>
237 private void DoPut(AssetRequestData rdata)
238 {
239 bool modified = false;
240 bool created = false;
241
242 AssetBase asset = null;
243
244 Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
245
246 if (rdata.Parameters.Length == 1)
247 {
248
249 rdata.initXmlReader();
250 XmlReader xml = rdata.reader;
251
252 if (!xml.ReadToFollowing("Asset"))
253 {
254 Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
255 rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
256 }
257
258 UUID uuid = new UUID(rdata.Parameters[0]);
259 asset = Rest.AssetServices.Get(uuid.ToString());
260
261 modified = (asset != null);
262 created = !modified;
263
264 asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
265 asset.Description = xml.GetAttribute("desc");
266 asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
267 asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
268 asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
269
270 if (asset.ID != rdata.Parameters[0])
271 {
272 Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}",
273 MsgId, rdata.Parameters[0], asset.ID);
274 }
275
276 Rest.AssetServices.Store(asset);
277
278 }
279 else
280 {
281 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
282 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
283 }
284
285 if (created)
286 {
287 rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
288 rdata.Complete(Rest.HttpStatusCodeCreated);
289 }
290 else
291 {
292 if (modified)
293 {
294 rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
295 rdata.Complete(Rest.HttpStatusCodeOK);
296 }
297 else
298 {
299 rdata.Complete(Rest.HttpStatusCodeNoContent);
300 }
301 }
302
303 rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
304
305 }
306
307 /// <summary>
308 /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
309 /// No parameters are required for POST, just thepayload.
310 /// </summary>
311
312 private void DoPost(AssetRequestData rdata)
313 {
314
315 bool modified = false;
316 bool created = false;
317
318 Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
319
320 if (rdata.Parameters.Length != 0)
321 {
322 Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path);
323 Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path);
324 }
325
326 rdata.initXmlReader();
327 XmlReader xml = rdata.reader;
328
329 if (!xml.ReadToFollowing("Asset"))
330 {
331 Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
332 rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
333 }
334
335 UUID uuid = new UUID(xml.GetAttribute("id"));
336 AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
337
338 modified = (asset != null);
339 created = !modified;
340
341 asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
342 asset.Description = xml.GetAttribute("desc");
343 asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
344 asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
345 asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
346
347 Rest.AssetServices.Store(asset);
348
349 if (created)
350 {
351 rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
352 rdata.Complete(Rest.HttpStatusCodeCreated);
353 }
354 else
355 {
356 if (modified)
357 {
358 rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
359 rdata.Complete(Rest.HttpStatusCodeOK);
360 }
361 else
362 {
363 rdata.Complete(Rest.HttpStatusCodeNoContent);
364 }
365 }
366
367 rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
368
369 }
370
371 /// <summary>
372 /// Asset processing has no special data area requirements.
373 /// </summary>
374
375 internal class AssetRequestData : RequestData
376 {
377 internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
378 : base(request, response, prefix)
379 {
380 }
381 }
382 }
383}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
deleted file mode 100644
index e79d2bd..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
+++ /dev/null
@@ -1,448 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Xml;
30using System.IO;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Framework.Servers;
34using OpenSim.Framework.Servers.HttpServer;
35
36namespace OpenSim.ApplicationPlugins.Rest.Inventory
37{
38 public class RestFileServices : IRest
39 {
40 private bool enabled = false;
41 private string qPrefix = "files";
42
43 // A simple constructor is used to handle any once-only
44 // initialization of working classes.
45
46 public RestFileServices()
47 {
48 Rest.Log.InfoFormat("{0} File services initializing", MsgId);
49 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
50
51 // If the handler specifies a relative path for its domain
52 // then we must add the standard absolute prefix, e.g. /admin
53
54 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
55 {
56 Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
57 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
58 Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
59 }
60
61 // Register interface using the fully-qualified prefix
62
63 Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate);
64
65 // Activate if all went OK
66
67 enabled = true;
68
69 Rest.Log.InfoFormat("{0} File services initialization complete", MsgId);
70 }
71
72 // Post-construction, pre-enabled initialization opportunity
73 // Not currently exploited.
74
75 public void Initialize()
76 {
77 }
78
79 // Called by the plug-in to halt REST processing. Local processing is
80 // disabled, and control blocks until all current processing has
81 // completed. No new processing will be started
82
83 public void Close()
84 {
85 enabled = false;
86 Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix);
87 }
88
89 // Properties
90
91 internal string MsgId
92 {
93 get { return Rest.MsgId; }
94 }
95
96 #region Interface
97
98 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
99 {
100 return (RequestData) new FileRequestData(request, response, prefix);
101 }
102
103 // Asset Handler
104
105 private void DoFile(RequestData rparm)
106 {
107 if (!enabled) return;
108
109 FileRequestData rdata = (FileRequestData) rparm;
110
111 Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix);
112
113 // Now that we know this is a serious attempt to
114 // access file data, we should find out who
115 // is asking, and make sure they are authorized
116 // to do so. We need to validate the caller's
117 // identity before revealing anything about the
118 // status quo. Authenticate throws an exception
119 // via Fail if no identity information is present.
120 //
121 // With the present HTTP server we can't use the
122 // builtin authentication mechanisms because they
123 // would be enforced for all in-bound requests.
124 // Instead we look at the headers ourselves and
125 // handle authentication directly.
126
127 try
128 {
129 if (!rdata.IsAuthenticated)
130 {
131 rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
132 }
133 }
134 catch (RestException e)
135 {
136 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
137 {
138 Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
139 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
140 rdata.request.Headers.Get("Authorization"));
141 }
142 else
143 {
144 Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
145 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
146 rdata.request.Headers.Get("Authorization"));
147 }
148 throw (e);
149 }
150
151 // Remove the prefix and what's left are the parameters. If we don't have
152 // the parameters we need, fail the request. Parameters do NOT include
153 // any supplied query values.
154
155 if (rdata.Parameters.Length > 0)
156 {
157 switch (rdata.method)
158 {
159 case "get" :
160 DoGet(rdata);
161 break;
162 case "put" :
163 DoPut(rdata);
164 break;
165 case "post" :
166 DoPost(rdata);
167 break;
168 case "delete" :
169 DoDelete(rdata);
170 break;
171 default :
172 Rest.Log.WarnFormat("{0} File: Method not supported: {1}",
173 MsgId, rdata.method);
174 rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
175 break;
176 }
177 }
178 else
179 {
180 Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId);
181 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
182 }
183
184 Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId);
185
186 }
187
188 #endregion Interface
189
190 /// <summary>
191 /// The only parameter we recognize is a UUID.If an asset with this identification is
192 /// found, it's content, base-64 encoded, is returned to the client.
193 /// </summary>
194
195 private void DoGet(FileRequestData rdata)
196 {
197
198 string path = String.Empty;
199
200 Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
201
202 if (rdata.Parameters.Length > 1)
203 {
204 try
205 {
206 path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
207 if (File.Exists(path))
208 {
209 Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path);
210 Byte[] data = File.ReadAllBytes(path);
211 rdata.initXmlWriter();
212 rdata.writer.WriteStartElement(String.Empty,"File",String.Empty);
213 rdata.writer.WriteAttributeString("name", path);
214 rdata.writer.WriteBase64(data,0,data.Length);
215 rdata.writer.WriteFullEndElement();
216 }
217 else
218 {
219 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path);
220 rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path));
221 }
222 }
223 catch (Exception e)
224 {
225 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message);
226 rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
227 path, e.Message));
228 }
229 }
230
231 rdata.Complete();
232 rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method));
233
234 }
235
236 /// <summary>
237 /// UPDATE existing item, if it exists. URI identifies the item in question.
238 /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
239 /// is decoded and stored in the database, identified by the supplied UUID.
240 /// </summary>
241 private void DoPut(FileRequestData rdata)
242 {
243 bool modified = false;
244 bool created = false;
245 string path = String.Empty;
246
247 Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
248
249 if (rdata.Parameters.Length > 1)
250 {
251 try
252 {
253 path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
254 bool maymod = File.Exists(path);
255
256 rdata.initXmlReader();
257 XmlReader xml = rdata.reader;
258
259 if (!xml.ReadToFollowing("File"))
260 {
261 Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
262 rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
263 }
264
265 Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
266
267 File.WriteAllBytes(path,data);
268 modified = maymod;
269 created = ! maymod;
270 }
271 catch (Exception e)
272 {
273 Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
274 e.Message);
275 }
276 }
277 else
278 {
279 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
280 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
281 }
282
283 if (created)
284 {
285 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
286 rdata.Complete(Rest.HttpStatusCodeCreated);
287 }
288 else
289 {
290 if (modified)
291 {
292 rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
293 rdata.Complete(Rest.HttpStatusCodeOK);
294 }
295 else
296 {
297 rdata.Complete(Rest.HttpStatusCodeNoContent);
298 }
299 }
300
301 rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
302
303 }
304
305 /// <summary>
306 /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
307 /// No parameters are required for POST, just thepayload.
308 /// </summary>
309
310 private void DoPost(FileRequestData rdata)
311 {
312
313 bool modified = false;
314 bool created = false;
315 string path = String.Empty;
316
317 Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
318
319 if (rdata.Parameters.Length > 1)
320 {
321 try
322 {
323 path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
324 bool maymod = File.Exists(path);
325
326 rdata.initXmlReader();
327 XmlReader xml = rdata.reader;
328
329 if (!xml.ReadToFollowing("File"))
330 {
331 Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
332 rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
333 }
334
335 Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
336
337 File.WriteAllBytes(path,data);
338 modified = maymod;
339 created = ! maymod;
340 }
341 catch (Exception e)
342 {
343 Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
344 e.Message);
345 }
346 }
347 else
348 {
349 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
350 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
351 }
352
353 if (created)
354 {
355 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
356 rdata.Complete(Rest.HttpStatusCodeCreated);
357 }
358 else
359 {
360 if (modified)
361 {
362 rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
363 rdata.Complete(Rest.HttpStatusCodeOK);
364 }
365 else
366 {
367 rdata.Complete(Rest.HttpStatusCodeNoContent);
368 }
369 }
370
371 rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
372
373 }
374
375 /// <summary>
376 /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
377 /// No parameters are required for POST, just thepayload.
378 /// </summary>
379
380 private void DoDelete(FileRequestData rdata)
381 {
382
383 bool modified = false;
384 bool created = false;
385 string path = String.Empty;
386
387 Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
388
389 if (rdata.Parameters.Length > 1)
390 {
391 try
392 {
393 path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
394
395 if (File.Exists(path))
396 {
397 File.Delete(path);
398 }
399 }
400 catch (Exception e)
401 {
402 Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
403 e.Message);
404 rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
405 path, e.Message));
406 }
407 }
408 else
409 {
410 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
411 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
412 }
413
414 if (created)
415 {
416 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
417 rdata.Complete(Rest.HttpStatusCodeCreated);
418 }
419 else
420 {
421 if (modified)
422 {
423 rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
424 rdata.Complete(Rest.HttpStatusCodeOK);
425 }
426 else
427 {
428 rdata.Complete(Rest.HttpStatusCodeNoContent);
429 }
430 }
431
432 rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
433
434 }
435
436 /// <summary>
437 /// File processing has no special data area requirements.
438 /// </summary>
439
440 internal class FileRequestData : RequestData
441 {
442 internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
443 : base(request, response, prefix)
444 {
445 }
446 }
447 }
448}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
deleted file mode 100644
index 072bd6f..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
+++ /dev/null
@@ -1,662 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenSim.Framework.Servers;
32using OpenSim.Framework.Servers.HttpServer;
33
34namespace OpenSim.ApplicationPlugins.Rest.Inventory
35{
36 /// <remarks>
37 /// The class signature reveals the roles that RestHandler plays.
38 ///
39 /// [1] It is a sub-class of RestPlugin. It inherits and extends
40 /// the functionality of this class, constraining it to the
41 /// specific needs of this REST implementation. This relates
42 /// to the plug-in mechanism supported by OpenSim, the specifics
43 /// of which are mostly hidden by RestPlugin.
44 /// [2] IRestHandler describes the interface that this class
45 /// exports to service implementations. This is the services
46 /// management interface.
47 /// [3] IHttpAgentHandler describes the interface that is exported
48 /// to the BaseHttpServer in support of this particular HTTP
49 /// processing model. This is the request interface of the
50 /// handler.
51 /// </remarks>
52
53 public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler
54 {
55 // Handler tables: both stream and REST are supported. The path handlers and their
56 // respective allocators are stored in separate tables.
57
58 internal Dictionary<string,RestMethodHandler> pathHandlers = new Dictionary<string,RestMethodHandler>();
59 internal Dictionary<string,RestMethodAllocator> pathAllocators = new Dictionary<string,RestMethodAllocator>();
60 internal Dictionary<string,RestStreamHandler> streamHandlers = new Dictionary<string,RestStreamHandler>();
61
62 #region local static state
63
64 private static bool handlersLoaded = false;
65 private static List<Type> classes = new List<Type>();
66 private static List<IRest> handlers = new List<IRest>();
67 private static Type[] parms = new Type[0];
68 private static Object[] args = new Object[0];
69
70 /// <summary>
71 /// This static initializer scans the ASSEMBLY for classes that
72 /// export the IRest interface and builds a list of them. These
73 /// are later activated by the handler. To add a new handler it
74 /// is only necessary to create a new services class that implements
75 /// the IRest interface, and recompile the handler. This gives
76 /// all of the build-time flexibility of a modular approach
77 /// while not introducing yet-another module loader. Note that
78 /// multiple assembles can still be built, each with its own set
79 /// of handlers. Examples of services classes are RestInventoryServices
80 /// and RestSkeleton.
81 /// </summary>
82
83 static RestHandler()
84 {
85 Module[] mods = Assembly.GetExecutingAssembly().GetModules();
86
87 foreach (Module m in mods)
88 {
89 Type[] types = m.GetTypes();
90 foreach (Type t in types)
91 {
92 try
93 {
94 if (t.GetInterface("IRest") != null)
95 {
96 classes.Add(t);
97 }
98 }
99 catch (Exception)
100 {
101 Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t);
102 Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t);
103 }
104 }
105 }
106 }
107
108 #endregion local static state
109
110 #region local instance state
111
112 /// <summary>
113 /// This routine loads all of the handlers discovered during
114 /// instance initialization.
115 /// A table of all loaded and successfully constructed handlers
116 /// is built, and this table is then used by the constructor to
117 /// initialize each of the handlers in turn.
118 /// NOTE: The loading process does not automatically imply that
119 /// the handler has registered any kind of an interface, that
120 /// may be (optionally) done by the handler either during
121 /// construction, or during initialization.
122 ///
123 /// I was not able to make this code work within a constructor
124 /// so it is isolated within this method.
125 /// </summary>
126
127 private void LoadHandlers()
128 {
129 lock (handlers)
130 {
131 if (!handlersLoaded)
132 {
133 ConstructorInfo ci;
134 Object ht;
135
136 foreach (Type t in classes)
137 {
138 try
139 {
140 ci = t.GetConstructor(parms);
141 ht = ci.Invoke(args);
142 handlers.Add((IRest)ht);
143 }
144 catch (Exception e)
145 {
146 Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message);
147 }
148 }
149 handlersLoaded = true;
150 }
151 }
152 }
153
154 #endregion local instance state
155
156 #region overriding properties
157
158 // These properties override definitions
159 // in the base class.
160
161 // Name is used to differentiate the message header.
162
163 public override string Name
164 {
165 get { return "HANDLER"; }
166 }
167
168 // Used to partition the .ini configuration space.
169
170 public override string ConfigName
171 {
172 get { return "RestHandler"; }
173 }
174
175 // We have to rename these because we want
176 // to be able to share the values with other
177 // classes in our assembly and the base
178 // names are protected.
179
180 public string MsgId
181 {
182 get { return base.MsgID; }
183 }
184
185 public string RequestId
186 {
187 get { return base.RequestID; }
188 }
189
190 #endregion overriding properties
191
192 #region overriding methods
193
194 /// <summary>
195 /// This method is called by OpenSimMain immediately after loading the
196 /// plugin and after basic server setup, but before running any server commands.
197 /// </summary>
198 /// <remarks>
199 /// Note that entries MUST be added to the active configuration files before
200 /// the plugin can be enabled.
201 /// </remarks>
202
203 public override void Initialise(OpenSimBase openSim)
204 {
205 try
206 {
207 // This plugin will only be enabled if the broader
208 // REST plugin mechanism is enabled.
209
210 //Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId);
211
212 base.Initialise(openSim);
213
214 // IsEnabled is implemented by the base class and
215 // reflects an overall RestPlugin status
216
217 if (!IsEnabled)
218 {
219 //Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId);
220 return;
221 }
222
223 Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name);
224 Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName);
225
226 // These are stored in static variables to make
227 // them easy to reach from anywhere in the assembly.
228
229 Rest.main = openSim;
230 if (Rest.main == null)
231 throw new Exception("OpenSim base pointer is null");
232
233 Rest.Plugin = this;
234 Rest.Config = Config;
235 Rest.Prefix = Prefix;
236 Rest.GodKey = GodKey;
237 Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate);
238 Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme);
239 Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure);
240 Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape);
241 Rest.Realm = Rest.Config.GetString("realm", Rest.Realm);
242 Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset);
243 Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill);
244 Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize);
245 Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled);
246
247 // Note: Odd spacing is required in the following strings
248
249 Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
250 (Rest.Authenticate ? "" : "not "));
251
252 Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId,
253 (Rest.Secure ? "" : "not "));
254
255 Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId,
256 (Rest.ExtendedEscape ? "" : "not "));
257
258 Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId,
259 (Rest.DumpAsset ? "" : "not "));
260
261 // The supplied prefix MUST be absolute
262
263 if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator)
264 {
265 Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix);
266 Rest.Log.InfoFormat("{0} Prefix changed to </{1}>", MsgId, Rest.Prefix);
267 Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix);
268 }
269
270 // If data dumping is requested, report on the chosen line
271 // length.
272
273 if (Rest.DumpAsset)
274 {
275 Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize);
276 }
277
278 // Load all of the handlers present in the
279 // assembly
280
281 // In principle, as we're an application plug-in,
282 // most of what needs to be done could be done using
283 // static resources, however the Open Sim plug-in
284 // model makes this an instance, so that's what we
285 // need to be.
286 // There is only one Communications manager per
287 // server, and by inference, only one each of the
288 // user, asset, and inventory servers. So we can cache
289 // those using a static initializer.
290 // We move all of this processing off to another
291 // services class to minimize overlap between function
292 // and infrastructure.
293
294 LoadHandlers();
295
296 // The intention of a post construction initializer
297 // is to allow for setup that is dependent upon other
298 // activities outside of the agency.
299
300 foreach (IRest handler in handlers)
301 {
302 try
303 {
304 handler.Initialize();
305 }
306 catch (Exception e)
307 {
308 Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message);
309 }
310 }
311
312 // Now that everything is setup we can proceed to
313 // add THIS agent to the HTTP server's handler list
314
315 // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
316 // have to be handled through the AddHttpHandler interface.
317// if (!AddAgentHandler(Rest.Name,this))
318// {
319// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
320// foreach (IRest handler in handlers)
321// {
322// handler.Close();
323// }
324// }
325
326 }
327 catch (Exception e)
328 {
329 Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message);
330 }
331 }
332
333 /// <summary>
334 /// In the interests of efficiency, and because we cannot determine whether
335 /// or not this instance will actually be harvested, we clobber the only
336 /// anchoring reference to the working state for this plug-in. What the
337 /// call to close does is irrelevant to this class beyond knowing that it
338 /// can nullify the reference when it returns.
339 /// To make sure everything is copacetic we make sure the primary interface
340 /// is disabled by deleting the handler from the HTTP server tables.
341 /// </summary>
342
343 public override void Close()
344 {
345 Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
346
347 // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
348 // have to be handled through the AddHttpHandler interface.
349// try
350// {
351// RemoveAgentHandler(Rest.Name, this);
352// }
353// catch (KeyNotFoundException){}
354
355 foreach (IRest handler in handlers)
356 {
357 handler.Close();
358 }
359 }
360
361 #endregion overriding methods
362
363 #region interface methods
364
365 /// <summary>
366 /// This method is called by the HTTP server to match an incoming
367 /// request. It scans all of the strings registered by the
368 /// underlying handlers and looks for the best match. It returns
369 /// true if a match is found.
370 /// The matching process could be made arbitrarily complex.
371 /// Note: The match is case-insensitive.
372 /// </summary>
373
374 public bool Match(OSHttpRequest request, OSHttpResponse response)
375 {
376
377 string path = request.RawUrl.ToLower();
378
379 // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId);
380
381 try
382 {
383 foreach (string key in pathHandlers.Keys)
384 {
385 // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key);
386
387 // Note that Match will not necessarily find the handler that will
388 // actually be used - it does no test for the "closest" fit. It
389 // simply reflects that at least one possible handler exists.
390
391 if (path.StartsWith(key))
392 {
393 // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
394
395 // This apparently odd evaluation is needed to prevent a match
396 // on anything other than a URI token boundary. Otherwise we
397 // may match on URL's that were not intended for this handler.
398
399 return (path.Length == key.Length ||
400 path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
401 }
402 }
403
404 path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path);
405
406 foreach (string key in streamHandlers.Keys)
407 {
408 // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key);
409
410 // Note that Match will not necessarily find the handler that will
411 // actually be used - it does no test for the "closest" fit. It
412 // simply reflects that at least one possible handler exists.
413
414 if (path.StartsWith(key))
415 {
416 // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
417
418 // This apparently odd evaluation is needed to prevent a match
419 // on anything other than a URI token boundary. Otherwise we
420 // may match on URL's that were not intended for this handler.
421
422 return (path.Length == key.Length ||
423 path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
424 }
425 }
426 }
427 catch (Exception e)
428 {
429 Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message);
430 }
431
432 return false;
433 }
434
435 /// <summary>
436 /// This is called by the HTTP server once the handler has indicated
437 /// that it is able to handle the request.
438 /// Preconditions:
439 /// [1] request != null and is a valid request object
440 /// [2] response != null and is a valid response object
441 /// Behavior is undefined if preconditions are not satisfied.
442 /// </summary>
443
444 public bool Handle(OSHttpRequest request, OSHttpResponse response)
445 {
446 bool handled;
447 base.MsgID = base.RequestID;
448
449 // Debug only
450
451 if (Rest.DEBUG)
452 {
453 Rest.Log.DebugFormat("{0} ENTRY", MsgId);
454 Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent);
455 Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod);
456
457 for (int i = 0; i < request.Headers.Count; i++)
458 {
459 Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>",
460 MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i));
461 }
462 Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl);
463 }
464
465 // If a path handler worked we're done, otherwise try any
466 // available stream handlers too.
467
468 try
469 {
470 handled = (FindPathHandler(request, response) ||
471 FindStreamHandler(request, response));
472 }
473 catch (Exception e)
474 {
475 // A raw exception indicates that something we weren't expecting has
476 // happened. This should always reflect a shortcoming in the plugin,
477 // or a failure to satisfy the preconditions. It should not reflect
478 // an error in the request itself. Under such circumstances the state
479 // of the request cannot be determined and we are obliged to mark it
480 // as 'handled'.
481
482 Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message);
483 handled = true;
484 }
485
486 Rest.Log.DebugFormat("{0} EXIT", MsgId);
487
488 return handled;
489 }
490
491 #endregion interface methods
492
493 /// <summary>
494 /// If there is a stream handler registered that can handle the
495 /// request, then fine. If the request is not matched, do
496 /// nothing.
497 /// Note: The selection is case-insensitive
498 /// </summary>
499
500 private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response)
501 {
502 RequestData rdata = new RequestData(request, response, String.Empty);
503
504 string bestMatch = String.Empty;
505 string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower();
506
507 Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path);
508
509 if (!IsEnabled)
510 {
511 return false;
512 }
513
514 foreach (string pattern in streamHandlers.Keys)
515 {
516 if (path.StartsWith(pattern))
517 {
518 if (pattern.Length > bestMatch.Length)
519 {
520 bestMatch = pattern;
521 }
522 }
523 }
524
525 // Handle using the best match available
526
527 if (bestMatch.Length > 0)
528 {
529 Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch);
530 RestStreamHandler handler = streamHandlers[bestMatch];
531 rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response);
532 rdata.AddHeader(rdata.response.ContentType,handler.ContentType);
533 rdata.Respond("FindStreamHandler Completion");
534 }
535
536 return rdata.handled;
537 }
538
539 /// <summary>
540 /// Add a stream handler for the designated HTTP method and path prefix.
541 /// If the handler is not enabled, the request is ignored. If the path
542 /// does not start with the REST prefix, it is added. If method-qualified
543 /// path has not already been registered, the method is added to the active
544 /// handler table.
545 /// </summary>
546 public void AddStreamHandler(string httpMethod, string path, RestMethod method)
547 {
548 if (!IsEnabled)
549 {
550 return;
551 }
552
553 if (!path.StartsWith(Rest.Prefix))
554 {
555 path = String.Format("{0}{1}", Rest.Prefix, path);
556 }
557
558 path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path);
559
560 // Conditionally add to the list
561
562 if (!streamHandlers.ContainsKey(path))
563 {
564 streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method));
565 Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path);
566 }
567 else
568 {
569 Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path);
570 }
571 }
572
573 /// <summary>
574 /// Given the supplied request/response, if the handler is enabled, the inbound
575 /// information is used to match an entry in the active path handler tables, using
576 /// the method-qualified path information. If a match is found, then the handler is
577 /// invoked. The result is the boolean result of the handler, or false if no
578 /// handler was located. The boolean indicates whether or not the request has been
579 /// handled, not whether or not the request was successful - that information is in
580 /// the response.
581 /// Note: The selection process is case-insensitive
582 /// </summary>
583
584 internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response)
585 {
586 RequestData rdata = null;
587 string bestMatch = null;
588
589 if (!IsEnabled)
590 {
591 return false;
592 }
593
594 // Conditionally add to the list
595
596 Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl);
597
598 foreach (string pattern in pathHandlers.Keys)
599 {
600 if (request.RawUrl.ToLower().StartsWith(pattern))
601 {
602 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
603 {
604 bestMatch = pattern;
605 }
606 }
607 }
608
609 if (!String.IsNullOrEmpty(bestMatch))
610 {
611 rdata = pathAllocators[bestMatch](request, response, bestMatch);
612
613 Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch);
614
615 try
616 {
617 pathHandlers[bestMatch](rdata);
618 }
619
620 // A plugin generated error indicates a request-related error
621 // that has been handled by the plugin.
622
623 catch (RestException r)
624 {
625 Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message);
626 }
627 }
628
629 return (rdata == null) ? false : rdata.handled;
630 }
631
632 /// <summary>
633 /// A method handler and a request allocator are stored using the designated
634 /// path as a key. If an entry already exists, it is replaced by the new one.
635 /// </summary>
636
637 public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
638 {
639 if (!IsEnabled)
640 {
641 return;
642 }
643
644 if (pathHandlers.ContainsKey(path))
645 {
646 Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path);
647 pathHandlers.Remove(path);
648 }
649
650 if (pathAllocators.ContainsKey(path))
651 {
652 Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path);
653 pathAllocators.Remove(path);
654 }
655
656 Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path);
657
658 pathHandlers.Add(path, mh);
659 pathAllocators.Add(path, ra);
660 }
661 }
662}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
deleted file mode 100644
index 536f167..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
+++ /dev/null
@@ -1,2343 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Globalization;
32using System.IO;
33using System.Threading;
34using System.Timers;
35using System.Xml;
36using OpenMetaverse;
37using OpenMetaverse.Imaging;
38using OpenSim.Framework;
39
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using Timer=System.Timers.Timer;
43
44namespace OpenSim.ApplicationPlugins.Rest.Inventory
45{
46 public class RestInventoryServices : IRest
47 {
48// private static readonly int PARM_USERID = 0;
49// private static readonly int PARM_PATH = 1;
50
51// private bool enabled = false;
52 private string qPrefix = "inventory";
53
54// private static readonly string PRIVATE_ROOT_NAME = "My Inventory";
55
56 /// <summary>
57 /// The constructor makes sure that the service prefix is absolute
58 /// and the registers the service handler and the allocator.
59 /// </summary>
60
61 public RestInventoryServices()
62 {
63 Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId);
64 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
65
66 // If a relative path was specified for the handler's domain,
67 // add the standard prefix to make it absolute, e.g. /admin
68
69 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
70 {
71 Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
72 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
73 Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
74 }
75
76 // Register interface using the absolute URI.
77
78 Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate);
79
80 // Activate if everything went OK
81
82// enabled = true;
83
84 Rest.Log.InfoFormat("{0} Inventory services initialization complete", MsgId);
85 }
86
87 /// <summary>
88 /// Post-construction, pre-enabled initialization opportunity
89 /// Not currently exploited.
90 /// </summary>
91
92 public void Initialize()
93 {
94 }
95
96 /// <summary>
97 /// Called by the plug-in to halt service processing. Local processing is
98 /// disabled.
99 /// </summary>
100
101 public void Close()
102 {
103// enabled = false;
104 Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId);
105 }
106
107 /// <summary>
108 /// This property is declared locally because it is used a lot and
109 /// brevity is nice.
110 /// </summary>
111 internal string MsgId
112 {
113 get { return Rest.MsgId; }
114 }
115
116 #region Interface
117
118 /// <summary>
119 /// The plugin (RestHandler) calls this method to allocate the request
120 /// state carrier for a new request. It is destroyed when the request
121 /// completes. All request-instance specific state is kept here. This
122 /// is registered when this service provider is registered.
123 /// </summary>
124 /// <param name=request>Inbound HTTP request information</param>
125 /// <param name=response>Outbound HTTP request information</param>
126 /// <param name=qPrefix>REST service domain prefix</param>
127 /// <returns>A RequestData instance suitable for this service</returns>
128 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
129 {
130 return (RequestData) new InventoryRequestData(request, response, prefix);
131 }
132
133 /// <summary>
134 /// This method is registered with the handler when this service provider
135 /// is initialized. It is called whenever the plug-in identifies this service
136 /// provider as the best match for a given request.
137 /// It handles all aspects of inventory REST processing, i.e. /admin/inventory
138 /// </summary>
139 /// <param name=hdata>A consolidated HTTP request work area</param>
140 private void DoInventory(RequestData hdata)
141 {
142// InventoryRequestData rdata = (InventoryRequestData) hdata;
143
144 Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId);
145
146 // !!! REFACTORING PROBLEM
147
148 //// If we're disabled, do nothing.
149
150 //if (!enabled)
151 //{
152 // return;
153 //}
154
155 //// Now that we know this is a serious attempt to
156 //// access inventory data, we should find out who
157 //// is asking, and make sure they are authorized
158 //// to do so. We need to validate the caller's
159 //// identity before revealing anything about the
160 //// status quo. Authenticate throws an exception
161 //// via Fail if no identity information is present.
162 ////
163 //// With the present HTTP server we can't use the
164 //// builtin authentication mechanisms because they
165 //// would be enforced for all in-bound requests.
166 //// Instead we look at the headers ourselves and
167 //// handle authentication directly.
168
169 //try
170 //{
171 // if (!rdata.IsAuthenticated)
172 // {
173 // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
174 // }
175 //}
176 //catch (RestException e)
177 //{
178 // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
179 // {
180 // Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
181 // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
182 // }
183 // else
184 // {
185 // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
186 // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
187 // }
188 // throw (e);
189 //}
190
191 //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
192
193 //// We can only get here if we are authorized
194 ////
195 //// The requestor may have specified an UUID or
196 //// a conjoined FirstName LastName string. We'll
197 //// try both. If we fail with the first, UUID,
198 //// attempt, we try the other. As an example, the
199 //// URI for a valid inventory request might be:
200 ////
201 //// http://<host>:<port>/admin/inventory/Arthur Dent
202 ////
203 //// Indicating that this is an inventory request for
204 //// an avatar named Arthur Dent. This is ALL that is
205 //// required to designate a GET for an entire
206 //// inventory.
207 ////
208
209
210 //// Do we have at least a user agent name?
211
212 //if (rdata.Parameters.Length < 1)
213 //{
214 // Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId);
215 // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
216 //}
217
218 //// The first parameter MUST be the agent identification, either an UUID
219 //// or a space-separated First-name Last-Name specification. We check for
220 //// an UUID first, if anyone names their character using a valid UUID
221 //// that identifies another existing avatar will cause this a problem...
222
223 //try
224 //{
225 // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
226 // Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
227 // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
228 //}
229 //catch
230 //{
231 // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
232 // if (names.Length == 2)
233 // {
234 // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
235 // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
236 // }
237 // else
238 // {
239 // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
240 // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
241 // }
242 //}
243
244 //// If the user profile is null then either the server is broken, or the
245 //// user is not known. We always assume the latter case.
246
247 //if (rdata.userProfile != null)
248 //{
249 // Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}",
250 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
251 //}
252 //else
253 //{
254 // Rest.Log.WarnFormat("{0} No profile for {1}", MsgId, rdata.path);
255 // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
256 //}
257
258 //// If we get to here, then we have effectively validated the user's
259 //// identity. Now we need to get the inventory. If the server does not
260 //// have the inventory, we reject the request with an appropriate explanation.
261 ////
262 //// Note that inventory retrieval is an asynchronous event, we use the rdata
263 //// class instance as the basis for our synchronization.
264 ////
265
266 //rdata.uuid = rdata.userProfile.ID;
267
268 //if (Rest.InventoryServices.HasInventoryForUser(rdata.uuid))
269 //{
270 // rdata.root = Rest.InventoryServices.GetRootFolder(rdata.uuid);
271
272 // Rest.Log.DebugFormat("{0} Inventory Root retrieved for {1} {2}",
273 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
274
275 // Rest.InventoryServices.GetUserInventory(rdata.uuid, rdata.GetUserInventory);
276
277 // Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}",
278 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
279
280 // lock (rdata)
281 // {
282 // if (!rdata.HaveInventory)
283 // {
284 // rdata.startWD(1000);
285 // rdata.timeout = false;
286 // Monitor.Wait(rdata);
287 // }
288 // }
289
290 // if (rdata.timeout)
291 // {
292 // Rest.Log.WarnFormat("{0} Inventory not available for {1} {2}. No response from service.",
293 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
294 // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory server not responding");
295 // }
296
297 // if (rdata.root == null)
298 // {
299 // Rest.Log.WarnFormat("{0} Inventory is not available [1] for agent {1} {2}",
300 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
301 // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory retrieval failed");
302 // }
303
304 //}
305 //else
306 //{
307 // Rest.Log.WarnFormat("{0} Inventory is not locally available for agent {1} {2}",
308 // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
309 // rdata.Fail(Rest.HttpStatusCodeNotFound, "no local inventory for user");
310 //}
311
312 //// If we get here, then we have successfully retrieved the user's information
313 //// and inventory information is now available locally.
314
315 //switch (rdata.method)
316 //{
317 // case Rest.HEAD : // Do the processing, set the status code, suppress entity
318 // DoGet(rdata);
319 // rdata.buffer = null;
320 // break;
321
322 // case Rest.GET : // Do the processing, set the status code, return entity
323 // DoGet(rdata);
324 // break;
325
326 // case Rest.PUT : // Update named element
327 // DoUpdate(rdata);
328 // break;
329
330 // case Rest.POST : // Add new information to identified context.
331 // DoExtend(rdata);
332 // break;
333
334 // case Rest.DELETE : // Delete information
335 // DoDelete(rdata);
336 // break;
337
338 // default :
339 // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
340 // MsgId, rdata.method, rdata.path);
341 // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
342 // String.Format("{0} not supported", rdata.method));
343 // break;
344 //}
345 }
346
347 #endregion Interface
348
349 #region method-specific processing
350
351 /// <summary>
352 /// This method implements GET processing for inventory.
353 /// Any remaining parameters are used to locate the
354 /// corresponding subtree based upon node name.
355 /// </summary>
356 /// <param name=rdata>HTTP service request work area</param>
357// private void DoGet(InventoryRequestData rdata)
358// {
359// rdata.initXmlWriter();
360//
361// rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty);
362//
363// // If there are additional parameters, then these represent
364// // a path relative to the root of the inventory. This path
365// // must be traversed before we format the sub-tree thus
366// // identified.
367//
368// traverse(rdata, rdata.root, PARM_PATH);
369//
370// // Close all open elements
371//
372// rdata.writer.WriteFullEndElement();
373//
374// // Indicate a successful request
375//
376// rdata.Complete();
377//
378// // Send the response to the user. The body will be implicitly
379// // constructed from the result of the XML writer.
380//
381// rdata.Respond(String.Format("Inventory {0} Normal completion", rdata.method));
382// }
383
384 /// <summary>
385 /// In the case of the inventory, and probably in general,
386 /// the distinction between PUT and POST is not always
387 /// easy to discern. The standard is badly worded in places,
388 /// and adding a node to a hierarchy can be viewed as
389 /// an addition, or as a modification to the inventory as
390 /// a whole. This is exacerbated by an unjustified lack of
391 /// consistency across different implementations.
392 ///
393 /// For OpenSim PUT is an update and POST is an addition. This
394 /// is the behavior required by the HTTP specification and
395 /// therefore as required by REST.
396 ///
397 /// The best way to explain the distinction is to
398 /// consider the relationship between the URI and the
399 /// enclosed entity. For PUT, the URI identifies the
400 /// actual entity to be modified or replaced, i.e. the
401 /// enclosed entity.
402 ///
403 /// If the operation is POST,then the URI describes the
404 /// context into which the new entity will be added.
405 ///
406 /// As an example, suppose the URI contains:
407 /// /admin/inventory/Clothing
408 ///
409 /// A PUT request will normally result in some modification of
410 /// the folder or item named "Clothing". Whereas a POST
411 /// request will normally add some new information into the
412 /// content identified by Clothing. It follows from this
413 /// that for POST, the element identified by the URI MUST
414 /// be a folder.
415 /// </summary>
416
417 /// <summary>
418 /// POST adds new information to the inventory in the
419 /// context identified by the URI.
420 /// </summary>
421 /// <param name=rdata>HTTP service request work area</param>
422// private void DoExtend(InventoryRequestData rdata)
423// {
424// bool created = false;
425// bool modified = false;
426// string newnode = String.Empty;
427//
428// // Resolve the context node specified in the URI. Entity
429// // data will be ADDED beneath this node. rdata already contains
430// // information about the current content of the user's
431// // inventory.
432//
433// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill);
434//
435// // Processing depends upon the type of inventory node
436// // identified in the URI. This is the CONTEXT for the
437// // change. We either got a context or we threw an
438// // exception.
439//
440// // It follows that we can only add information if the URI
441// // has identified a folder. So only a type of folder is supported
442// // in this case.
443//
444// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
445// typeof(InventoryFolderImpl) == InventoryNode.GetType())
446// {
447// // Cast the context node appropriately.
448//
449// InventoryFolderBase context = (InventoryFolderBase) InventoryNode;
450//
451// Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}",
452// MsgId, rdata.method, rdata.path);
453//
454// // Reconstitute the inventory sub-tree from the XML supplied in the entity.
455// // The result is a stand-alone inventory subtree, not yet integrated into the
456// // existing tree. An inventory collection consists of three components:
457// // [1] A (possibly empty) set of folders.
458// // [2] A (possibly empty) set of items.
459// // [3] A (possibly empty) set of assets.
460// // If all of these are empty, then the POST is a harmless no-operation.
461//
462// XmlInventoryCollection entity = ReconstituteEntity(rdata);
463//
464// // Inlined assets can be included in entity. These must be incorporated into
465// // the asset database before we attempt to update the inventory. If anything
466// // fails, return a failure to requestor.
467//
468// if (entity.Assets.Count > 0)
469// {
470// Rest.Log.DebugFormat("{0} Adding {1} assets to server",
471// MsgId, entity.Assets.Count);
472//
473// foreach (AssetBase asset in entity.Assets)
474// {
475// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
476// MsgId, asset.ID, asset.Type, asset.Name);
477// Rest.AssetServices.Store(asset);
478//
479// created = true;
480// rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>",
481// asset.Name, asset.ID));
482//
483// if (Rest.DEBUG && Rest.DumpAsset)
484// {
485// Rest.Dump(asset.Data);
486// }
487// }
488// }
489//
490// // Modify the context using the collection of folders and items
491// // returned in the XmlInventoryCollection.
492//
493// foreach (InventoryFolderBase folder in entity.Folders)
494// {
495// InventoryFolderBase found;
496//
497// // If the parentID is zero, then this folder is going
498// // into the root folder identified by the URI. The requestor
499// // may have already set the parent ID explicitly, in which
500// // case we don't have to do it here.
501//
502// if (folder.ParentID == UUID.Zero || folder.ParentID == context.ID)
503// {
504// if (newnode != String.Empty)
505// {
506// Rest.Log.DebugFormat("{0} Too many resources", MsgId);
507// rdata.Fail(Rest.HttpStatusCodeBadRequest, "only one root entity is allowed");
508// }
509// folder.ParentID = context.ID;
510// newnode = folder.Name;
511// }
512//
513// // Search the existing inventory for an existing entry. If
514// // we have one, we need to decide if it has really changed.
515// // It could just be present as (unnecessary) context, and we
516// // don't want to waste time updating the database in that
517// // case, OR, it could be being moved from another location
518// // in which case an update is most certainly necessary.
519//
520// found = null;
521//
522// foreach (InventoryFolderBase xf in rdata.folders)
523// {
524// // Compare identifying attribute
525// if (xf.ID == folder.ID)
526// {
527// found = xf;
528// break;
529// }
530// }
531//
532// if (found != null && FolderHasChanged(folder,found))
533// {
534// Rest.Log.DebugFormat("{0} Updating existing folder", MsgId);
535// Rest.InventoryServices.MoveFolder(folder);
536//
537// modified = true;
538// rdata.appendStatus(String.Format("<p> Created folder {0}, UUID {1} <p>",
539// folder.Name, folder.ID));
540// }
541// else
542// {
543// Rest.Log.DebugFormat("{0} Adding new folder", MsgId);
544// Rest.InventoryServices.AddFolder(folder);
545//
546// created = true;
547// rdata.appendStatus(String.Format("<p> Modified folder {0}, UUID {1} <p>",
548// folder.Name, folder.ID));
549// }
550// }
551//
552// // Now we repeat a similar process for the items included
553// // in the entity.
554//
555// foreach (InventoryItemBase item in entity.Items)
556// {
557// InventoryItemBase found = null;
558//
559// // If the parentID is zero, then this is going
560// // directly into the root identified by the URI.
561//
562// if (item.Folder == UUID.Zero)
563// {
564// item.Folder = context.ID;
565// }
566//
567// // Determine whether this is a new item or a
568// // replacement definition.
569//
570// foreach (InventoryItemBase xi in rdata.items)
571// {
572// // Compare identifying attribute
573// if (xi.ID == item.ID)
574// {
575// found = xi;
576// break;
577// }
578// }
579//
580// if (found != null && ItemHasChanged(item, found))
581// {
582// Rest.Log.DebugFormat("{0} Updating item {1} {2} {3} {4} {5}",
583// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name);
584// Rest.InventoryServices.UpdateItem(item);
585// modified = true;
586// rdata.appendStatus(String.Format("<p> Modified item {0}, UUID {1} <p>", item.Name, item.ID));
587// }
588// else
589// {
590// Rest.Log.DebugFormat("{0} Adding item {1} {2} {3} {4} {5}",
591// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name);
592// Rest.InventoryServices.AddItem(item);
593// created = true;
594// rdata.appendStatus(String.Format("<p> Created item {0}, UUID {1} <p>", item.Name, item.ID));
595// }
596// }
597//
598// if (created)
599// {
600// // Must include a location header with a URI that identifies the new resource.
601// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}/{3}",
602// rdata.hostname, rdata.port,rdata.path,newnode));
603// rdata.Complete(Rest.HttpStatusCodeCreated);
604// }
605// else
606// {
607// if (modified)
608// {
609// rdata.Complete(Rest.HttpStatusCodeOK);
610// }
611// else
612// {
613// rdata.Complete(Rest.HttpStatusCodeNoContent);
614// }
615// }
616//
617// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
618// }
619// else
620// {
621// Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}",
622// MsgId, rdata.method, rdata.path, InventoryNode.GetType());
623// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid resource context");
624// }
625// }
626
627 /// <summary>
628 /// PUT updates the URI-identified element in the inventory. This
629 /// is actually far more flexible than it might at first sound. For
630 /// PUT the URI serves two purposes:
631 /// [1] It identifies the user whose inventory is to be
632 /// processed.
633 /// [2] It optionally specifies a subtree of the inventory
634 /// that is to be used to resolve any relative subtree
635 /// specifications in the entity. If nothing is specified
636 /// then the whole of the private inventory is implied.
637 /// Please note that the subtree specified by the URI is only relevant
638 /// to an entity containing a URI relative specification, i.e. one or
639 /// more elements do not specify parent folder information. These
640 /// elements will be implicitly referenced within the context identified
641 /// by the URI.
642 /// If an element in the entity specifies an explicit parent folder, then
643 /// that parent is effective, regardless of any value specified in the
644 /// URI. If the parent does not exist, then the element, and any dependent
645 /// elements, are ignored. This case is actually detected and handled
646 /// during the reconstitution process.
647 /// </summary>
648 /// <param name=rdata>HTTP service request work area</param>
649// private void DoUpdate(InventoryRequestData rdata)
650// {
651// int count = 0;
652// bool created = false;
653// bool modified = false;
654//
655// // Resolve the inventory node that is to be modified.
656// // rdata already contains information about the current
657// // content of the user's inventory.
658//
659// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill);
660//
661// // As long as we have a node, then we have something
662// // meaningful to do, unlike POST. So we reconstitute the
663// // subtree before doing anything else. Note that we
664// // etiher got a valid node or we threw an exception.
665//
666// XmlInventoryCollection entity = ReconstituteEntity(rdata);
667//
668// // Incorporate any inlined assets first. Any failures
669// // will terminate the request.
670//
671// if (entity.Assets.Count > 0)
672// {
673// Rest.Log.DebugFormat("{0} Adding {1} assets to server",
674// MsgId, entity.Assets.Count);
675//
676// foreach (AssetBase asset in entity.Assets)
677// {
678// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
679// MsgId, asset.ID, asset.Type, asset.Name);
680//
681// // The asset was validated during the collection process
682//
683// Rest.AssetServices.Store(asset);
684//
685// created = true;
686// rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.ID));
687//
688// if (Rest.DEBUG && Rest.DumpAsset)
689// {
690// Rest.Dump(asset.Data);
691// }
692// }
693// }
694//
695// // The URI specifies either a folder or an item to be updated.
696// //
697// // The root node in the entity will replace the node identified
698// // by the URI. This means the parent will remain the same, but
699// // any or all attributes associated with the named element
700// // will change.
701// //
702// // If the inventory collection contains an element with a zero
703// // parent ID, then this is taken to be the replacement for the
704// // named node. The collection MAY also specify an explicit
705// // parent ID, in this case it MAY identify the same parent as
706// // the current node, or it MAY specify a different parent,
707// // indicating that the folder is being moved in addition to any
708// // other modifications being made.
709//
710// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
711// typeof(InventoryFolderImpl) == InventoryNode.GetType())
712// {
713// bool rfound = false;
714// InventoryFolderBase uri = (InventoryFolderBase) InventoryNode;
715// InventoryFolderBase xml = null;
716//
717// // If the entity to be replaced resolved to be the root
718// // directory itself (My Inventory), then make sure that
719// // the supplied data include as appropriately typed and
720// // named folder. Note that we can;t rule out the possibility
721// // of a sub-directory being called "My Inventory", so that
722// // is anticipated.
723//
724// if (uri == rdata.root)
725// {
726// foreach (InventoryFolderBase folder in entity.Folders)
727// {
728// if ((rfound = (folder.Name == PRIVATE_ROOT_NAME)))
729// {
730// if ((rfound = (folder.ParentID == UUID.Zero)))
731// break;
732// }
733// }
734//
735// if (!rfound)
736// {
737// Rest.Log.DebugFormat("{0} {1}: Path <{2}> will result in loss of inventory",
738// MsgId, rdata.method, rdata.path);
739// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid inventory structure");
740// }
741// }
742//
743// // Scan the set of folders in the entity collection for an
744// // entry that matches the context folder. It is assumed that
745// // the only reliable indicator of this is a zero UUID (using
746// // implicit context), or the parent's UUID matches that of the
747// // URI designated node (explicit context). We don't allow
748// // ambiguity in this case because this is POST and we are
749// // supposed to be modifying a specific node.
750// // We assign any element IDs required as an economy; we don't
751// // want to iterate over the fodler set again if it can be
752// // helped.
753//
754// foreach (InventoryFolderBase folder in entity.Folders)
755// {
756// if (folder.ParentID == uri.ParentID ||
757// folder.ParentID == UUID.Zero)
758// {
759// folder.ParentID = uri.ParentID;
760// xml = folder;
761// count++;
762// }
763// }
764//
765// // More than one entry is ambiguous. Other folders should be
766// // added using the POST verb.
767//
768// if (count > 1)
769// {
770// Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous",
771// MsgId, rdata.method, rdata.path);
772// rdata.Fail(Rest.HttpStatusCodeConflict, "context is ambiguous");
773// }
774//
775// // Exactly one entry means we ARE replacing the node
776// // identified by the URI. So we delete the old folder
777// // by moving it to the trash and then purging it.
778// // We then add all of the folders and items we
779// // included in the entity. The subtree has been
780// // modified.
781//
782// if (count == 1)
783// {
784// InventoryFolderBase TrashCan = GetTrashCan(rdata);
785//
786// // All went well, so we generate a UUID is one is
787// // needed.
788//
789// if (xml.ID == UUID.Zero)
790// {
791// xml.ID = UUID.Random();
792// }
793//
794// uri.ParentID = TrashCan.ID;
795// Rest.InventoryServices.MoveFolder(uri);
796// Rest.InventoryServices.PurgeFolder(TrashCan);
797// modified = true;
798// }
799//
800// // Now, regardelss of what they represent, we
801// // integrate all of the elements in the entity.
802//
803// foreach (InventoryFolderBase f in entity.Folders)
804// {
805// rdata.appendStatus(String.Format("<p>Moving folder {0} UUID {1} <p>", f.Name, f.ID));
806// Rest.InventoryServices.MoveFolder(f);
807// }
808//
809// foreach (InventoryItemBase it in entity.Items)
810// {
811// rdata.appendStatus(String.Format("<p>Storing item {0} UUID {1} <p>", it.Name, it.ID));
812// Rest.InventoryServices.AddItem(it);
813// }
814// }
815//
816// /// <summary>
817// /// URI specifies an item to be updated
818// /// </summary>
819// /// <remarks>
820// /// The entity must contain a single item node to be
821// /// updated. ID and Folder ID must be correct.
822// /// </remarks>
823//
824// else
825// {
826// InventoryItemBase uri = (InventoryItemBase) InventoryNode;
827// InventoryItemBase xml = null;
828//
829// if (entity.Folders.Count != 0)
830// {
831// Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>",
832// MsgId, rdata.method, rdata.path);
833// rdata.Fail(Rest.HttpStatusCodeBadRequest, "folder is not allowed");
834// }
835//
836// if (entity.Items.Count > 1)
837// {
838// Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>",
839// MsgId, rdata.method, rdata.path);
840// rdata.Fail(Rest.HttpStatusCodeBadRequest, "too may items");
841// }
842//
843// xml = entity.Items[0];
844//
845// if (xml.ID == UUID.Zero)
846// {
847// xml.ID = UUID.Random();
848// }
849//
850// // If the folder reference has changed, then this item is
851// // being moved. Otherwise we'll just delete the old, and
852// // add in the new.
853//
854// // Delete the old item
855//
856// List<UUID> uuids = new List<UUID>();
857// uuids.Add(uri.ID);
858// Rest.InventoryServices.DeleteItems(uri.Owner, uuids);
859//
860// // Add the new item to the inventory
861//
862// Rest.InventoryServices.AddItem(xml);
863//
864// rdata.appendStatus(String.Format("<p>Storing item {0} UUID {1} <p>", xml.Name, xml.ID));
865// }
866//
867// if (created)
868// {
869// rdata.Complete(Rest.HttpStatusCodeCreated);
870// }
871// else
872// {
873// if (modified)
874// {
875// rdata.Complete(Rest.HttpStatusCodeOK);
876// }
877// else
878// {
879// rdata.Complete(Rest.HttpStatusCodeNoContent);
880// }
881// }
882//
883// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
884// }
885
886 /// <summary>
887 /// Arguably the most damaging REST interface. It deletes the inventory
888 /// item or folder identified by the URI.
889 ///
890 /// We only process if the URI identified node appears to exist
891 /// We do not test for success because we either get a context,
892 /// or an exception is thrown.
893 ///
894 /// Folders are deleted by moving them to another folder and then
895 /// purging that folder. We'll do that by creating a temporary
896 /// sub-folder in the TrashCan and purging that folder's
897 /// contents. If we can't can it, we don't delete it...
898 /// So, if no trashcan is available, the request does nothing.
899 /// Items are summarily deleted.
900 ///
901 /// In the interests of safety, a delete request should normally
902 /// be performed using UUID, as a name might identify several
903 /// elements.
904 /// </summary>
905 /// <param name=rdata>HTTP service request work area</param>
906// private void DoDelete(InventoryRequestData rdata)
907// {
908// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, false);
909//
910// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
911// typeof(InventoryFolderImpl) == InventoryNode.GetType())
912// {
913// InventoryFolderBase TrashCan = GetTrashCan(rdata);
914//
915// InventoryFolderBase folder = (InventoryFolderBase) InventoryNode;
916// Rest.Log.DebugFormat("{0} {1}: Folder {2} will be deleted",
917// MsgId, rdata.method, rdata.path);
918// folder.ParentID = TrashCan.ID;
919// Rest.InventoryServices.MoveFolder(folder);
920// Rest.InventoryServices.PurgeFolder(TrashCan);
921//
922// rdata.appendStatus(String.Format("<p>Deleted folder {0} UUID {1} <p>", folder.Name, folder.ID));
923// }
924//
925// // Deleting items is much more straight forward.
926//
927// else
928// {
929// InventoryItemBase item = (InventoryItemBase) InventoryNode;
930// Rest.Log.DebugFormat("{0} {1}: Item {2} will be deleted",
931// MsgId, rdata.method, rdata.path);
932// List<UUID> uuids = new List<UUID>();
933// uuids.Add(item.ID);
934// Rest.InventoryServices.DeleteItems(item.Owner, uuids);
935// rdata.appendStatus(String.Format("<p>Deleted item {0} UUID {1} <p>", item.Name, item.ID));
936// }
937//
938// rdata.Complete();
939// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
940// }
941
942#endregion method-specific processing
943
944 /// <summary>
945 /// This method is called to obtain the OpenSim inventory object identified
946 /// by the supplied URI. This may be either an Item or a Folder, so a suitably
947 /// ambiguous return type is employed (Object). This method recurses as
948 /// necessary to process the designated hierarchy.
949 ///
950 /// If we reach the end of the URI then we return the contextual folder to
951 /// our caller.
952 ///
953 /// If we are not yet at the end of the URI we attempt to find a child folder
954 /// and if we succeed we recurse.
955 ///
956 /// If this is the last node, then we look to see if this is an item. If it is,
957 /// we return that item.
958 ///
959 /// If we reach the end of an inventory path and the URI si not yet exhausted,
960 /// then if 'fill' is specified, we create the intermediate nodes.
961 ///
962 /// Otherwise we fail the request on the ground of an invalid URI.
963 ///
964 /// An ambiguous request causes the request to fail.
965 ///
966 /// </summary>
967 /// <param name=rdata>HTTP service request work area</param>
968 /// <param name=folder>The folder to be searched (parent)</param>
969 /// <param name=pi>URI parameter index</param>
970 /// <param name=fill>Should missing path members be created?</param>
971
972 private Object getInventoryNode(InventoryRequestData rdata,
973 InventoryFolderBase folder,
974 int pi, bool fill)
975 {
976 InventoryFolderBase foundf = null;
977 int fk = 0;
978
979 Rest.Log.DebugFormat("{0} Searching folder {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
980
981 // We have just run off the end of the parameter sequence
982
983 if (pi >= rdata.Parameters.Length)
984 {
985 return folder;
986 }
987
988 // There are more names in the parameter sequence,
989 // look for the folder named by param[pi] as a
990 // child of the folder supplied as an argument.
991 // Note that a UUID may have been supplied as the
992 // identifier (it is the ONLY guaranteed unambiguous
993 // option.
994
995 if (rdata.folders != null)
996 {
997 foreach (InventoryFolderBase f in rdata.folders)
998 {
999 // Look for the present node in the directory list
1000 if (f.ParentID == folder.ID &&
1001 (f.Name == rdata.Parameters[pi] ||
1002 f.ID.ToString() == rdata.Parameters[pi]))
1003 {
1004 foundf = f;
1005 fk++;
1006 }
1007 }
1008 }
1009
1010 // If more than one node matched, then the path, as specified
1011 // is ambiguous.
1012
1013 if (fk > 1)
1014 {
1015 Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous",
1016 MsgId, rdata.method, rdata.path);
1017 rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous");
1018 }
1019
1020 // If we find a match, then the method
1021 // increment the parameter index, and calls itself
1022 // passing the found folder as the new context.
1023
1024 if (foundf != null)
1025 {
1026 return getInventoryNode(rdata, foundf, pi+1, fill);
1027 }
1028
1029 // No folders that match. Perhaps this parameter identifies an item? If
1030 // it does, then it MUST also be the last name in the sequence.
1031
1032 if (pi == rdata.Parameters.Length-1)
1033 {
1034 if (rdata.items != null)
1035 {
1036 int k = 0;
1037 InventoryItemBase li = null;
1038 foreach (InventoryItemBase i in rdata.items)
1039 {
1040 if (i.Folder == folder.ID &&
1041 (i.Name == rdata.Parameters[pi] ||
1042 i.ID.ToString() == rdata.Parameters[pi]))
1043 {
1044 li = i;
1045 k++;
1046 }
1047 }
1048 if (k == 1)
1049 {
1050 return li;
1051 }
1052 else if (k > 1)
1053 {
1054 Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous",
1055 MsgId, rdata.method, rdata.path);
1056 rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous");
1057 }
1058 }
1059 }
1060
1061 // If fill is enabled, then we must create the missing intermediate nodes.
1062 // And of course, even this is not straightforward. All intermediate nodes
1063 // are obviously folders, but the last node may be a folder or an item.
1064
1065 if (fill)
1066 {
1067 }
1068
1069 // No fill, so abandon the request
1070
1071 Rest.Log.DebugFormat("{0} {1}: Resource {2} not found",
1072 MsgId, rdata.method, rdata.path);
1073 rdata.Fail(Rest.HttpStatusCodeNotFound,
1074 String.Format("resource {0}:{1} not found", rdata.method, rdata.path));
1075
1076 return null; /* Never reached */
1077 }
1078
1079 /// <summary>
1080 /// This routine traverse the inventory's structure until the end-point identified
1081 /// in the URI is reached, the remainder of the inventory (if any) is then formatted
1082 /// and returned to the requestor.
1083 ///
1084 /// Note that this method is only interested in those folder that match elements of
1085 /// the URI supplied by the requestor, so once a match is fund, the processing does
1086 /// not need to consider any further elements.
1087 ///
1088 /// Only the last element in the URI should identify an item.
1089 /// </summary>
1090 /// <param name=rdata>HTTP service request work area</param>
1091 /// <param name=folder>The folder to be searched (parent)</param>
1092 /// <param name=pi>URI parameter index</param>
1093
1094 private void traverse(InventoryRequestData rdata, InventoryFolderBase folder, int pi)
1095 {
1096 Rest.Log.DebugFormat("{0} Traverse[initial] : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
1097
1098 if (rdata.folders != null)
1099 {
1100 // If there was only one parameter (avatar name), then the entire
1101 // inventory is being requested.
1102
1103 if (rdata.Parameters.Length == 1)
1104 {
1105 formatInventory(rdata, rdata.root, String.Empty);
1106 }
1107
1108 // Has the client specified the root directory name explicitly?
1109 // if yes, then we just absorb the reference, because the folder
1110 // we start looking in for a match *is* the root directory. If there
1111 // are more parameters remaining we tarverse, otehrwise it's time
1112 // to format. Otherwise,we consider the "My Inventory" to be implied
1113 // and we just traverse normally.
1114
1115 else if (folder.ID.ToString() == rdata.Parameters[pi] ||
1116 folder.Name == rdata.Parameters[pi])
1117 {
1118 // Length is -1 because the avatar name is a parameter
1119 if (pi<(rdata.Parameters.Length-1))
1120 {
1121 traverseInventory(rdata, folder, pi+1);
1122 }
1123 else
1124 {
1125 formatInventory(rdata, folder, String.Empty);
1126 }
1127 }
1128 else
1129 {
1130 traverseInventory(rdata, folder, pi);
1131 }
1132
1133 return;
1134 }
1135 }
1136
1137 /// <summary>
1138 /// This is the recursive method. I've separated them in this way so that
1139 /// we do not have to waste cycles on any first-case-only processing.
1140 /// </summary>
1141
1142 private void traverseInventory(InventoryRequestData rdata, InventoryFolderBase folder, int pi)
1143 {
1144 int fk = 0;
1145 InventoryFolderBase ffound = null;
1146 InventoryItemBase ifound = null;
1147
1148 Rest.Log.DebugFormat("{0} Traverse Folder : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
1149
1150 foreach (InventoryFolderBase f in rdata.folders)
1151 {
1152 if (f.ParentID == folder.ID &&
1153 (f.Name == rdata.Parameters[pi] ||
1154 f.ID.ToString() == rdata.Parameters[pi]))
1155 {
1156 fk++;
1157 ffound = f;
1158 }
1159 }
1160
1161 // If this is the last element in the parameter sequence, then
1162 // it is reasonable to check for an item. All intermediate nodes
1163 // MUST be folders.
1164
1165 if (pi == rdata.Parameters.Length-1)
1166 {
1167 // Only if there are any items, and there pretty much always are.
1168
1169 if (rdata.items != null)
1170 {
1171 foreach (InventoryItemBase i in rdata.items)
1172 {
1173 if (i.Folder == folder.ID &&
1174 (i.Name == rdata.Parameters[pi] ||
1175 i.ID.ToString() == rdata.Parameters[pi]))
1176 {
1177 fk++;
1178 ifound = i;
1179 }
1180 }
1181 }
1182 }
1183
1184 if (fk == 1)
1185 {
1186 if (ffound != null)
1187 {
1188 if (pi < rdata.Parameters.Length-1)
1189 {
1190 traverseInventory(rdata, ffound, pi+1);
1191 }
1192 else
1193 {
1194 formatInventory(rdata, ffound, String.Empty);
1195 }
1196 return;
1197 }
1198 else
1199 {
1200 // Fetching an Item has a special significance. In this
1201 // case we also want to fetch the associated asset.
1202 // To make it interesting, we'll do this via redirection.
1203 string asseturl = String.Format("http://{0}:{1}/{2}{3}{4}", rdata.hostname, rdata.port,
1204 "admin/assets",Rest.UrlPathSeparator,ifound.AssetID.ToString());
1205 rdata.Redirect(asseturl,Rest.PERMANENT);
1206 Rest.Log.DebugFormat("{0} Never Reached", MsgId);
1207 }
1208 }
1209 else if (fk > 1)
1210 {
1211 rdata.Fail(Rest.HttpStatusCodeConflict,
1212 String.Format("ambiguous element ({0}) in path specified: <{1}>",
1213 pi, rdata.path));
1214 }
1215
1216 Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>",
1217 MsgId, rdata.path);
1218 rdata.Fail(Rest.HttpStatusCodeNotFound,String.Format("no such item/folder : {0}",
1219 rdata.Parameters[pi]));
1220
1221 }
1222
1223 /// <summary>
1224 /// This method generates XML that describes an instance of InventoryFolderBase.
1225 /// It recurses as necessary to reflect a folder hierarchy, and calls formatItem
1226 /// to generate XML for any items encountered along the way.
1227 /// The indentation parameter is solely for the benefit of trace record
1228 /// formatting.
1229 /// </summary>
1230 /// <param name=rdata>HTTP service request work area</param>
1231 /// <param name=folder>The folder to be searched (parent)</param>
1232 /// <param name=indent>pretty print indentation</param>
1233 private void formatInventory(InventoryRequestData rdata, InventoryFolderBase folder, string indent)
1234 {
1235 if (Rest.DEBUG)
1236 {
1237 Rest.Log.DebugFormat("{0} Folder : {1} {2} {3} type = {4}",
1238 MsgId, folder.ID, indent, folder.Name, folder.Type);
1239 indent += "\t";
1240 }
1241
1242 // Start folder item
1243
1244 rdata.writer.WriteStartElement(String.Empty,"Folder",String.Empty);
1245 rdata.writer.WriteAttributeString("name",String.Empty,folder.Name);
1246 rdata.writer.WriteAttributeString("uuid",String.Empty,folder.ID.ToString());
1247 rdata.writer.WriteAttributeString("parent",String.Empty,folder.ParentID.ToString());
1248 rdata.writer.WriteAttributeString("owner",String.Empty,folder.Owner.ToString());
1249 rdata.writer.WriteAttributeString("type",String.Empty,folder.Type.ToString());
1250 rdata.writer.WriteAttributeString("version",String.Empty,folder.Version.ToString());
1251
1252 if (rdata.folders != null)
1253 {
1254 foreach (InventoryFolderBase f in rdata.folders)
1255 {
1256 if (f.ParentID == folder.ID)
1257 {
1258 formatInventory(rdata, f, indent);
1259 }
1260 }
1261 }
1262
1263 if (rdata.items != null)
1264 {
1265 foreach (InventoryItemBase i in rdata.items)
1266 {
1267 if (i.Folder == folder.ID)
1268 {
1269 formatItem(rdata, i, indent);
1270 }
1271 }
1272 }
1273
1274 // End folder item
1275
1276 rdata.writer.WriteEndElement();
1277 }
1278
1279 /// <summary>
1280 /// This method generates XML that describes an instance of InventoryItemBase.
1281 /// </summary>
1282 /// <param name="rdata">HTTP service request work area</param>
1283 /// <param name="i">The item to be formatted</param>
1284 /// <param name="indent">Pretty print indentation</param>
1285 private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent)
1286 {
1287 Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}",
1288 MsgId, i.ID, indent, i.Name, i.InvType, i.AssetType);
1289
1290 rdata.writer.WriteStartElement(String.Empty, "Item", String.Empty);
1291
1292 rdata.writer.WriteAttributeString("name", String.Empty, i.Name);
1293 rdata.writer.WriteAttributeString("desc", String.Empty, i.Description);
1294 rdata.writer.WriteAttributeString("uuid", String.Empty, i.ID.ToString());
1295 rdata.writer.WriteAttributeString("folder", String.Empty, i.Folder.ToString());
1296 rdata.writer.WriteAttributeString("owner", String.Empty, i.Owner.ToString());
1297 rdata.writer.WriteAttributeString("creator", String.Empty, i.CreatorId);
1298 rdata.writer.WriteAttributeString("creatordata", String.Empty, i.CreatorData);
1299 rdata.writer.WriteAttributeString("creationdate", String.Empty, i.CreationDate.ToString());
1300 rdata.writer.WriteAttributeString("invtype", String.Empty, i.InvType.ToString());
1301 rdata.writer.WriteAttributeString("assettype", String.Empty, i.AssetType.ToString());
1302 rdata.writer.WriteAttributeString("groupowned", String.Empty, i.GroupOwned.ToString());
1303 rdata.writer.WriteAttributeString("groupid", String.Empty, i.GroupID.ToString());
1304 rdata.writer.WriteAttributeString("saletype", String.Empty, i.SaleType.ToString());
1305 rdata.writer.WriteAttributeString("saleprice", String.Empty, i.SalePrice.ToString());
1306 rdata.writer.WriteAttributeString("flags", String.Empty, i.Flags.ToString());
1307
1308 rdata.writer.WriteStartElement(String.Empty, "Permissions", String.Empty);
1309 rdata.writer.WriteAttributeString("current", String.Empty, i.CurrentPermissions.ToString("X"));
1310 rdata.writer.WriteAttributeString("next", String.Empty, i.NextPermissions.ToString("X"));
1311 rdata.writer.WriteAttributeString("group", String.Empty, i.GroupPermissions.ToString("X"));
1312 rdata.writer.WriteAttributeString("everyone", String.Empty, i.EveryOnePermissions.ToString("X"));
1313 rdata.writer.WriteAttributeString("base", String.Empty, i.BasePermissions.ToString("X"));
1314 rdata.writer.WriteEndElement();
1315
1316 rdata.writer.WriteElementString("Asset", i.AssetID.ToString());
1317
1318 rdata.writer.WriteEndElement();
1319 }
1320
1321 /// <summary>
1322 /// This method creates a "trashcan" folder to support folder and item
1323 /// deletions by this interface. The xisting trash folder is found and
1324 /// this folder is created within it. It is called "tmp" to indicate to
1325 /// the client that it is OK to delete this folder. The REST interface
1326 /// will recreate the folder on an as-required basis.
1327 /// If the trash can cannot be created, then by implication the request
1328 /// that required it cannot be completed, and it fails accordingly.
1329 /// </summary>
1330 /// <param name=rdata>HTTP service request work area</param>
1331 private InventoryFolderBase GetTrashCan(InventoryRequestData rdata)
1332 {
1333 InventoryFolderBase TrashCan = null;
1334
1335 foreach (InventoryFolderBase f in rdata.folders)
1336 {
1337 if (f.Name == "Trash")
1338 {
1339 foreach (InventoryFolderBase t in rdata.folders)
1340 {
1341 if (t.Name == "tmp")
1342 {
1343 TrashCan = t;
1344 }
1345 }
1346 if (TrashCan == null)
1347 {
1348 TrashCan = new InventoryFolderBase();
1349 TrashCan.Name = "tmp";
1350 TrashCan.ID = UUID.Random();
1351 TrashCan.Version = 1;
1352 TrashCan.Type = (short) AssetType.TrashFolder;
1353 TrashCan.ParentID = f.ID;
1354 TrashCan.Owner = f.Owner;
1355 Rest.InventoryServices.AddFolder(TrashCan);
1356 }
1357 }
1358 }
1359
1360 if (TrashCan == null)
1361 {
1362 Rest.Log.DebugFormat("{0} No Trash Can available", MsgId);
1363 rdata.Fail(Rest.HttpStatusCodeServerError, "unable to create trash can");
1364 }
1365
1366 return TrashCan;
1367 }
1368
1369 /// <summary>
1370 /// Make sure that an unchanged folder is not unnecessarily
1371 /// processed.
1372 /// </summary>
1373 /// <param name=newf>Folder obtained from enclosed entity</param>
1374 /// <param name=oldf>Folder obtained from the user's inventory</param>
1375 private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf)
1376 {
1377 return (newf.Name != oldf.Name
1378 || newf.ParentID != oldf.ParentID
1379 || newf.Owner != oldf.Owner
1380 || newf.Type != oldf.Type
1381 || newf.Version != oldf.Version
1382 );
1383 }
1384
1385 /// <summary>
1386 /// Make sure that an unchanged item is not unnecessarily
1387 /// processed.
1388 /// </summary>
1389 /// <param name=newf>Item obtained from enclosed entity</param>
1390 /// <param name=oldf>Item obtained from the user's inventory</param>
1391 private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf)
1392 {
1393 return (newf.Name != oldf.Name
1394 || newf.Folder != oldf.Folder
1395 || newf.Description != oldf.Description
1396 || newf.Owner != oldf.Owner
1397 || newf.CreatorId != oldf.CreatorId
1398 || newf.AssetID != oldf.AssetID
1399 || newf.GroupID != oldf.GroupID
1400 || newf.GroupOwned != oldf.GroupOwned
1401 || newf.InvType != oldf.InvType
1402 || newf.AssetType != oldf.AssetType
1403 );
1404 }
1405
1406 /// <summary>
1407 /// This method is called by PUT and POST to create an XmlInventoryCollection
1408 /// instance that reflects the content of the entity supplied on the request.
1409 /// Any elements in the completed collection whose UUID is zero, are
1410 /// considered to be located relative to the end-point identified int he
1411 /// URI. In this way, an entire sub-tree can be conveyed in a single REST
1412 /// PUT or POST request.
1413 ///
1414 /// A new instance of XmlInventoryCollection is created and, if the request
1415 /// has an entity, it is more completely initialized. thus, if no entity was
1416 /// provided the collection is valid, but empty.
1417 ///
1418 /// The entity is then scanned and each tag is processed to produce the
1419 /// appropriate inventory elements. At the end f the scan, teh XmlInventoryCollection
1420 /// will reflect the subtree described by the entity.
1421 ///
1422 /// This is a very flexible mechanism, the entity may contain arbitrary,
1423 /// discontiguous tree fragments, or may contain single element. The caller is
1424 /// responsible for integrating this collection (and ensuring that any
1425 /// missing parent IDs are resolved).
1426 /// </summary>
1427 /// <param name=rdata>HTTP service request work area</param>
1428 internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata)
1429 {
1430 Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId);
1431
1432 XmlInventoryCollection ic = new XmlInventoryCollection();
1433
1434 if (rdata.request.HasEntityBody)
1435 {
1436 Rest.Log.DebugFormat("{0} Entity present", MsgId);
1437
1438 ic.init(rdata);
1439
1440 try
1441 {
1442 while (ic.xml.Read())
1443 {
1444 switch (ic.xml.NodeType)
1445 {
1446 case XmlNodeType.Element:
1447 Rest.Log.DebugFormat("{0} StartElement: <{1}>",
1448 MsgId, ic.xml.Name);
1449
1450 switch (ic.xml.Name)
1451 {
1452 case "Folder":
1453 Rest.Log.DebugFormat("{0} Processing {1} element",
1454 MsgId, ic.xml.Name);
1455 CollectFolder(ic);
1456 break;
1457 case "Item":
1458 Rest.Log.DebugFormat("{0} Processing {1} element",
1459 MsgId, ic.xml.Name);
1460 CollectItem(ic);
1461 break;
1462 case "Asset":
1463 Rest.Log.DebugFormat("{0} Processing {1} element",
1464 MsgId, ic.xml.Name);
1465 CollectAsset(ic);
1466 break;
1467 case "Permissions":
1468 Rest.Log.DebugFormat("{0} Processing {1} element",
1469 MsgId, ic.xml.Name);
1470 CollectPermissions(ic);
1471 break;
1472 default:
1473 Rest.Log.DebugFormat("{0} Ignoring {1} element",
1474 MsgId, ic.xml.Name);
1475 break;
1476 }
1477
1478 // This stinks, but the ReadElement call above not only reads
1479 // the imbedded data, but also consumes the end tag for Asset
1480 // and moves the element pointer on to the containing Item's
1481 // element-end, however, if there was a permissions element
1482 // following, it would get us to the start of that..
1483 if (ic.xml.NodeType == XmlNodeType.EndElement &&
1484 ic.xml.Name == "Item")
1485 {
1486 Validate(ic);
1487 }
1488 break;
1489
1490 case XmlNodeType.EndElement :
1491 switch (ic.xml.Name)
1492 {
1493 case "Folder":
1494 Rest.Log.DebugFormat("{0} Completing {1} element",
1495 MsgId, ic.xml.Name);
1496 ic.Pop();
1497 break;
1498 case "Item":
1499 Rest.Log.DebugFormat("{0} Completing {1} element",
1500 MsgId, ic.xml.Name);
1501 Validate(ic);
1502 break;
1503 case "Asset":
1504 Rest.Log.DebugFormat("{0} Completing {1} element",
1505 MsgId, ic.xml.Name);
1506 break;
1507 case "Permissions":
1508 Rest.Log.DebugFormat("{0} Completing {1} element",
1509 MsgId, ic.xml.Name);
1510 break;
1511 default:
1512 Rest.Log.DebugFormat("{0} Ignoring {1} element",
1513 MsgId, ic.xml.Name);
1514 break;
1515 }
1516 break;
1517
1518 default:
1519 Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>",
1520 MsgId, ic.xml.NodeType, ic.xml.Value);
1521 break;
1522 }
1523 }
1524 }
1525 catch (XmlException e)
1526 {
1527 Rest.Log.WarnFormat("{0} XML parsing error: {1}", MsgId, e.Message);
1528 throw e;
1529 }
1530 catch (Exception e)
1531 {
1532 Rest.Log.WarnFormat("{0} Unexpected XML parsing error: {1}", MsgId, e.Message);
1533 throw e;
1534 }
1535 }
1536 else
1537 {
1538 Rest.Log.DebugFormat("{0} Entity absent", MsgId);
1539 }
1540
1541 if (Rest.DEBUG)
1542 {
1543 Rest.Log.DebugFormat("{0} Reconstituted entity", MsgId);
1544 Rest.Log.DebugFormat("{0} {1} assets", MsgId, ic.Assets.Count);
1545 Rest.Log.DebugFormat("{0} {1} folder", MsgId, ic.Folders.Count);
1546 Rest.Log.DebugFormat("{0} {1} items", MsgId, ic.Items.Count);
1547 }
1548
1549 return ic;
1550 }
1551
1552 /// <summary>
1553 /// This method creates an inventory Folder from the
1554 /// information supplied in the request's entity.
1555 /// A folder instance is created and initialized to reflect
1556 /// default values. These values are then overridden
1557 /// by information supplied in the entity.
1558 /// If context was not explicitly provided, then the
1559 /// appropriate ID values are determined.
1560 /// </summary>
1561
1562 private void CollectFolder(XmlInventoryCollection ic)
1563 {
1564 Rest.Log.DebugFormat("{0} Interpret folder element", MsgId);
1565
1566 InventoryFolderBase result = new InventoryFolderBase();
1567
1568 // Default values
1569
1570 result.Name = String.Empty;
1571 result.ID = UUID.Zero;
1572 result.Owner = ic.UserID;
1573 result.ParentID = UUID.Zero; // Context
1574 result.Type = (short) AssetType.Folder;
1575 result.Version = 1;
1576
1577 if (ic.xml.HasAttributes)
1578 {
1579 for (int i = 0; i < ic.xml.AttributeCount; i++)
1580 {
1581 ic.xml.MoveToAttribute(i);
1582 switch (ic.xml.Name)
1583 {
1584 case "name":
1585 result.Name = ic.xml.Value;
1586 break;
1587 case "uuid":
1588 result.ID = new UUID(ic.xml.Value);
1589 break;
1590 case "parent":
1591 result.ParentID = new UUID(ic.xml.Value);
1592 break;
1593 case "owner":
1594 result.Owner = new UUID(ic.xml.Value);
1595 break;
1596 case "type":
1597 result.Type = Int16.Parse(ic.xml.Value);
1598 break;
1599 case "version":
1600 result.Version = UInt16.Parse(ic.xml.Value);
1601 break;
1602 default:
1603 Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}",
1604 MsgId, ic.xml.Name, ic.xml.Value);
1605 ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute <{0}>",
1606 ic.xml.Name));
1607 break;
1608 }
1609 }
1610 }
1611
1612 ic.xml.MoveToElement();
1613
1614 // The client is relying upon the reconstitution process
1615 // to determine the parent's UUID based upon context. This
1616 // is necessary where a new folder may have been
1617 // introduced.
1618
1619 if (result.ParentID == UUID.Zero)
1620 {
1621 result.ParentID = ic.Parent();
1622 }
1623 else
1624 {
1625 bool found = false;
1626
1627 foreach (InventoryFolderBase parent in ic.rdata.folders)
1628 {
1629 if (parent.ID == result.ParentID)
1630 {
1631 found = true;
1632 break;
1633 }
1634 }
1635
1636 if (!found)
1637 {
1638 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}",
1639 MsgId, ic.Item.Folder, result.ID);
1640 ic.Fail(Rest.HttpStatusCodeBadRequest, "invalid parent");
1641 }
1642 }
1643
1644 // This is a new folder, so no existing UUID is available
1645 // or appropriate
1646
1647 if (result.ID == UUID.Zero)
1648 {
1649 result.ID = UUID.Random();
1650 }
1651
1652 // Treat this as a new context. Any other information is
1653 // obsolete as a consequence.
1654
1655 ic.Push(result);
1656 }
1657
1658 /// <summary>
1659 /// This method is called to handle the construction of an Item
1660 /// instance from the supplied request entity. It is called
1661 /// whenever an Item start tag is detected.
1662 /// An instance of an Item is created and initialized to default
1663 /// values. These values are then overridden from values supplied
1664 /// as attributes to the Item element.
1665 /// This item is then stored in the XmlInventoryCollection and
1666 /// will be verified by Validate.
1667 /// All context is reset whenever the effective folder changes
1668 /// or an item is successfully validated.
1669 /// </summary>
1670 private void CollectItem(XmlInventoryCollection ic)
1671 {
1672 Rest.Log.DebugFormat("{0} Interpret item element", MsgId);
1673
1674 InventoryItemBase result = new InventoryItemBase();
1675
1676 result.Name = String.Empty;
1677 result.Description = String.Empty;
1678 result.ID = UUID.Zero;
1679 result.Folder = UUID.Zero;
1680 result.Owner = ic.UserID;
1681 result.CreatorId = ic.UserID.ToString();
1682 result.AssetID = UUID.Zero;
1683 result.GroupID = UUID.Zero;
1684 result.GroupOwned = false;
1685 result.InvType = (int) InventoryType.Unknown;
1686 result.AssetType = (int) AssetType.Unknown;
1687
1688 if (ic.xml.HasAttributes)
1689 {
1690 for (int i = 0; i < ic.xml.AttributeCount; i++)
1691 {
1692 ic.xml.MoveToAttribute(i);
1693
1694 switch (ic.xml.Name)
1695 {
1696 case "name":
1697 result.Name = ic.xml.Value;
1698 break;
1699 case "desc":
1700 result.Description = ic.xml.Value;
1701 break;
1702 case "uuid":
1703 result.ID = new UUID(ic.xml.Value);
1704 break;
1705 case "folder":
1706 result.Folder = new UUID(ic.xml.Value);
1707 break;
1708 case "owner":
1709 result.Owner = new UUID(ic.xml.Value);
1710 break;
1711 case "invtype":
1712 result.InvType = Int32.Parse(ic.xml.Value);
1713 break;
1714 case "creator":
1715 result.CreatorId = ic.xml.Value;
1716 break;
1717 case "assettype":
1718 result.AssetType = Int32.Parse(ic.xml.Value);
1719 break;
1720 case "groupowned":
1721 result.GroupOwned = Boolean.Parse(ic.xml.Value);
1722 break;
1723 case "groupid":
1724 result.GroupID = new UUID(ic.xml.Value);
1725 break;
1726 case "flags":
1727 result.Flags = UInt32.Parse(ic.xml.Value);
1728 break;
1729 case "creationdate":
1730 result.CreationDate = Int32.Parse(ic.xml.Value);
1731 break;
1732 case "saletype":
1733 result.SaleType = Byte.Parse(ic.xml.Value);
1734 break;
1735 case "saleprice":
1736 result.SalePrice = Int32.Parse(ic.xml.Value);
1737 break;
1738
1739 default:
1740 Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}",
1741 MsgId, ic.xml.Name, ic.xml.Value);
1742 ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute",
1743 ic.xml.Name));
1744 break;
1745 }
1746 }
1747 }
1748
1749 ic.xml.MoveToElement();
1750
1751 ic.Push(result);
1752 }
1753
1754 /// <summary>
1755 /// This method assembles an asset instance from the
1756 /// information supplied in the request's entity. It is
1757 /// called as a result of detecting a start tag for a
1758 /// type of Asset.
1759 /// The information is collected locally, and an asset
1760 /// instance is created only if the basic XML parsing
1761 /// completes successfully.
1762 /// Default values for all parts of the asset are
1763 /// established before overriding them from the supplied
1764 /// XML.
1765 /// If an asset has inline=true as an attribute, then
1766 /// the element contains the data representing the
1767 /// asset. This is saved as the data component.
1768 /// inline=false means that the element's payload is
1769 /// simply the UUID of the asset referenced by the
1770 /// item being constructed.
1771 /// An asset, if created is stored in the
1772 /// XmlInventoryCollection
1773 /// </summary>
1774 private void CollectAsset(XmlInventoryCollection ic)
1775 {
1776 Rest.Log.DebugFormat("{0} Interpret asset element", MsgId);
1777
1778 string name = String.Empty;
1779 string desc = String.Empty;
1780 sbyte type = (sbyte) AssetType.Unknown;
1781 bool temp = false;
1782 bool local = false;
1783
1784 // This is not a persistent attribute
1785 bool inline = false;
1786
1787 UUID uuid = UUID.Zero;
1788
1789 // Attribute is optional
1790 if (ic.xml.HasAttributes)
1791 {
1792 for (int i = 0; i < ic.xml.AttributeCount; i++)
1793 {
1794 ic.xml.MoveToAttribute(i);
1795 switch (ic.xml.Name)
1796 {
1797 case "name" :
1798 name = ic.xml.Value;
1799 break;
1800
1801 case "type" :
1802 type = SByte.Parse(ic.xml.Value);
1803 break;
1804
1805 case "description" :
1806 desc = ic.xml.Value;
1807 break;
1808
1809 case "temporary" :
1810 temp = Boolean.Parse(ic.xml.Value);
1811 break;
1812
1813 case "uuid" :
1814 uuid = new UUID(ic.xml.Value);
1815 break;
1816
1817 case "inline" :
1818 inline = Boolean.Parse(ic.xml.Value);
1819 break;
1820
1821 case "local" :
1822 local = Boolean.Parse(ic.xml.Value);
1823 break;
1824
1825 default :
1826 Rest.Log.DebugFormat("{0} Asset: Unrecognized attribute: {1}:{2}",
1827 MsgId, ic.xml.Name, ic.xml.Value);
1828 ic.Fail(Rest.HttpStatusCodeBadRequest,
1829 String.Format("unrecognized attribute <{0}>", ic.xml.Name));
1830 break;
1831 }
1832 }
1833 }
1834
1835 ic.xml.MoveToElement();
1836
1837 // If this is a reference to an existing asset, just store the
1838 // asset ID into the item.
1839
1840 if (!inline)
1841 {
1842 if (ic.Item != null)
1843 {
1844 ic.Item.AssetID = new UUID(ic.xml.ReadElementContentAsString());
1845 Rest.Log.DebugFormat("{0} Asset ID supplied: {1}", MsgId, ic.Item.AssetID);
1846 }
1847 else
1848 {
1849 Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId);
1850 ic.Fail(Rest.HttpStatusCodeBadRequest, "no context for asset");
1851 }
1852 }
1853
1854 // Otherwise, generate an asset ID, store that into the item, and
1855 // create an entry in the asset list for the inlined asset. But
1856 // only if the size is non-zero.
1857
1858 else
1859 {
1860 AssetBase asset = null;
1861 string b64string = null;
1862
1863 // Generate a UUID if none were given, and generally none should
1864 // be. Ever.
1865
1866 if (uuid == UUID.Zero)
1867 {
1868 uuid = UUID.Random();
1869 }
1870
1871 // Create AssetBase entity to hold the inlined asset
1872
1873 asset = new AssetBase(uuid, name, type, UUID.Zero.ToString());
1874
1875 asset.Description = desc;
1876 asset.Local = local;
1877 asset.Temporary = temp;
1878
1879 b64string = ic.xml.ReadElementContentAsString();
1880
1881 Rest.Log.DebugFormat("{0} Data length is {1}", MsgId, b64string.Length);
1882 Rest.Log.DebugFormat("{0} Data content starts with: \n\t<{1}>", MsgId,
1883 b64string.Substring(0, b64string.Length > 132 ? 132 : b64string.Length));
1884
1885 asset.Data = Convert.FromBase64String(b64string);
1886
1887 // Ensure the asset always has some kind of data component
1888
1889 if (asset.Data == null)
1890 {
1891 asset.Data = new byte[1];
1892 }
1893
1894 // If this is in the context of an item, establish
1895 // a link with the item in context.
1896
1897 if (ic.Item != null && ic.Item.AssetID == UUID.Zero)
1898 {
1899 ic.Item.AssetID = uuid;
1900 }
1901
1902 ic.Push(asset);
1903 }
1904 }
1905
1906 /// <summary>
1907 /// Store any permissions information provided by the request.
1908 /// This overrides the default permissions set when the
1909 /// XmlInventoryCollection object was created.
1910 /// </summary>
1911 private void CollectPermissions(XmlInventoryCollection ic)
1912 {
1913 if (ic.xml.HasAttributes)
1914 {
1915 for (int i = 0; i < ic.xml.AttributeCount; i++)
1916 {
1917 ic.xml.MoveToAttribute(i);
1918 switch (ic.xml.Name)
1919 {
1920 case "current":
1921 ic.CurrentPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
1922 break;
1923 case "next":
1924 ic.NextPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
1925 break;
1926 case "group":
1927 ic.GroupPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
1928 break;
1929 case "everyone":
1930 ic.EveryOnePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
1931 break;
1932 case "base":
1933 ic.BasePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
1934 break;
1935 default:
1936 Rest.Log.DebugFormat("{0} Permissions: invalid attribute {1}:{2}",
1937 MsgId,ic.xml.Name, ic.xml.Value);
1938 ic.Fail(Rest.HttpStatusCodeBadRequest,
1939 String.Format("invalid attribute <{0}>", ic.xml.Name));
1940 break;
1941 }
1942 }
1943 }
1944
1945 ic.xml.MoveToElement();
1946 }
1947
1948 /// <summary>
1949 /// This method is called whenever an Item has been successfully
1950 /// reconstituted from the request's entity.
1951 /// It uses the information curren tin the XmlInventoryCollection
1952 /// to complete the item's specification, including any implied
1953 /// context and asset associations.
1954 /// It fails the request if any necessary item or asset information
1955 /// is missing.
1956 /// </summary>
1957
1958 private void Validate(XmlInventoryCollection ic)
1959 {
1960 // There really should be an item present if we've
1961 // called validate. So fail if there is not.
1962
1963 if (ic.Item == null)
1964 {
1965 Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId);
1966 ic.Fail(Rest.HttpStatusCodeBadRequest, "request parse error");
1967 }
1968
1969 // Every item is required to have a name (via REST anyway)
1970
1971 if (ic.Item.Name == String.Empty)
1972 {
1973 Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId);
1974 ic.Fail(Rest.HttpStatusCodeBadRequest, "item name required");
1975 }
1976
1977 // An item MUST have an asset ID. AssetID should never be zero
1978 // here. It should always get set from the information stored
1979 // when the Asset element was processed.
1980
1981 if (ic.Item.AssetID == UUID.Zero)
1982 {
1983 Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId);
1984 Rest.Log.InfoFormat("{0} Asset information is missing", MsgId);
1985 ic.Fail(Rest.HttpStatusCodeBadRequest, "asset information required");
1986 }
1987
1988 // If the item is new, then assign it an ID
1989
1990 if (ic.Item.ID == UUID.Zero)
1991 {
1992 ic.Item.ID = UUID.Random();
1993 }
1994
1995 // If the context is being implied, obtain the current
1996 // folder item's ID. If it was specified explicitly, make
1997 // sure that theparent folder exists.
1998
1999 if (ic.Item.Folder == UUID.Zero)
2000 {
2001 ic.Item.Folder = ic.Parent();
2002 }
2003 else
2004 {
2005 bool found = false;
2006
2007 foreach (InventoryFolderBase parent in ic.rdata.folders)
2008 {
2009 if (parent.ID == ic.Item.Folder)
2010 {
2011 found = true;
2012 break;
2013 }
2014 }
2015
2016 if (!found)
2017 {
2018 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}",
2019 MsgId, ic.Item.Folder, ic.Item.ID);
2020 ic.Fail(Rest.HttpStatusCodeBadRequest, "parent information required");
2021 }
2022 }
2023
2024 // If this is an inline asset being constructed in the context
2025 // of a new Item, then use the itm's name here too.
2026
2027 if (ic.Asset != null)
2028 {
2029 if (ic.Asset.Name == String.Empty)
2030 ic.Asset.Name = ic.Item.Name;
2031 if (ic.Asset.Description == String.Empty)
2032 ic.Asset.Description = ic.Item.Description;
2033 }
2034
2035 // Assign permissions
2036
2037 ic.Item.CurrentPermissions = ic.CurrentPermissions;
2038 ic.Item.EveryOnePermissions = ic.EveryOnePermissions;
2039 ic.Item.BasePermissions = ic.BasePermissions;
2040 ic.Item.GroupPermissions = ic.GroupPermissions;
2041 ic.Item.NextPermissions = ic.NextPermissions;
2042
2043 // If no type was specified for this item, we can attempt to
2044 // infer something from the file type maybe. This is NOT as
2045 // good as having type be specified in the XML.
2046
2047 if (ic.Item.AssetType == (int) AssetType.Unknown ||
2048 ic.Item.InvType == (int) InventoryType.Unknown)
2049 {
2050 Rest.Log.DebugFormat("{0} Attempting to infer item type", MsgId);
2051
2052 string[] parts = ic.Item.Name.Split(Rest.CA_PERIOD);
2053
2054 if (Rest.DEBUG)
2055 {
2056 for (int i = 0; i < parts.Length; i++)
2057 {
2058 Rest.Log.DebugFormat("{0} Name part {1} : {2}",
2059 MsgId, i, parts[i]);
2060 }
2061 }
2062
2063 // If the associated item name is multi-part, then maybe
2064 // the last part will indicate the item type - if we're
2065 // lucky.
2066
2067 if (parts.Length > 1)
2068 {
2069 Rest.Log.DebugFormat("{0} File type is {1}",
2070 MsgId, parts[parts.Length - 1]);
2071 switch (parts[parts.Length - 1])
2072 {
2073 case "jpeg2000" :
2074 case "jpeg-2000" :
2075 case "jpg2000" :
2076 case "jpg-2000" :
2077 Rest.Log.DebugFormat("{0} Type {1} inferred",
2078 MsgId, parts[parts.Length-1]);
2079 if (ic.Item.AssetType == (int) AssetType.Unknown)
2080 ic.Item.AssetType = (int) AssetType.ImageJPEG;
2081 if (ic.Item.InvType == (int) InventoryType.Unknown)
2082 ic.Item.InvType = (int) InventoryType.Texture;
2083 break;
2084 case "jpg" :
2085 case "jpeg" :
2086 Rest.Log.DebugFormat("{0} Type {1} inferred",
2087 MsgId, parts[parts.Length - 1]);
2088 if (ic.Item.AssetType == (int) AssetType.Unknown)
2089 ic.Item.AssetType = (int) AssetType.ImageJPEG;
2090 if (ic.Item.InvType == (int) InventoryType.Unknown)
2091 ic.Item.InvType = (int) InventoryType.Texture;
2092 break;
2093 case "tga" :
2094 if (parts[parts.Length - 2].IndexOf("_texture") != -1)
2095 {
2096 if (ic.Item.AssetType == (int) AssetType.Unknown)
2097 ic.Item.AssetType = (int) AssetType.TextureTGA;
2098 if (ic.Item.InvType == (int) AssetType.Unknown)
2099 ic.Item.InvType = (int) InventoryType.Texture;
2100 }
2101 else
2102 {
2103 if (ic.Item.AssetType == (int) AssetType.Unknown)
2104 ic.Item.AssetType = (int) AssetType.ImageTGA;
2105 if (ic.Item.InvType == (int) InventoryType.Unknown)
2106 ic.Item.InvType = (int) InventoryType.Snapshot;
2107 }
2108 break;
2109 default :
2110 Rest.Log.DebugFormat("{0} Asset/Inventory type could not be inferred for {1}",
2111 MsgId,ic.Item.Name);
2112 break;
2113 }
2114 }
2115 }
2116
2117 /// If this is a TGA remember the fact
2118
2119 if (ic.Item.AssetType == (int) AssetType.TextureTGA ||
2120 ic.Item.AssetType == (int) AssetType.ImageTGA)
2121 {
2122 Bitmap temp;
2123 Stream tgadata = new MemoryStream(ic.Asset.Data);
2124
2125 temp = LoadTGAClass.LoadTGA(tgadata);
2126 try
2127 {
2128 ic.Asset.Data = OpenJPEG.EncodeFromImage(temp, true);
2129 }
2130 catch (DllNotFoundException)
2131 {
2132 Rest.Log.ErrorFormat("OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", ic.Item.Name);
2133 ic.Asset.Data = new Byte[0];
2134 }
2135 catch (IndexOutOfRangeException)
2136 {
2137 Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name);
2138 ic.Asset.Data = new Byte[0];
2139 }
2140 catch (Exception)
2141 {
2142 Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name);
2143 ic.Asset.Data = new Byte[0];
2144 }
2145 }
2146
2147 ic.reset();
2148 }
2149
2150 #region Inventory RequestData extension
2151
2152 internal class InventoryRequestData : RequestData
2153 {
2154 /// <summary>
2155 /// These are the inventory specific request/response state
2156 /// extensions.
2157 /// </summary>
2158
2159 internal UUID uuid = UUID.Zero;
2160 internal bool HaveInventory = false;
2161 internal ICollection<InventoryFolderImpl> folders = null;
2162 internal ICollection<InventoryItemBase> items = null;
2163 internal UserProfileData userProfile = null;
2164 internal InventoryFolderBase root = null;
2165 internal bool timeout = false;
2166 internal Timer watchDog = new Timer();
2167
2168 internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
2169 : base(request, response, prefix)
2170 {
2171 }
2172
2173 internal void startWD(double interval)
2174 {
2175 Rest.Log.DebugFormat("{0} Setting watchdog", MsgId);
2176 watchDog.Elapsed += new ElapsedEventHandler(OnTimeOut);
2177 watchDog.Interval = interval;
2178 watchDog.AutoReset = false;
2179 watchDog.Enabled = true;
2180 lock (watchDog)
2181 watchDog.Start();
2182
2183 }
2184
2185 internal void stopWD()
2186 {
2187 Rest.Log.DebugFormat("{0} Reset watchdog", MsgId);
2188 lock (watchDog)
2189 watchDog.Stop();
2190 }
2191
2192 /// <summary>
2193 /// This is the callback method required by the inventory watchdog. The
2194 /// requestor issues an inventory request and then blocks until the
2195 /// request completes, or this method signals the monitor.
2196 /// </summary>
2197
2198 private void OnTimeOut(object sender, ElapsedEventArgs args)
2199 {
2200 Rest.Log.DebugFormat("{0} Asynchronous inventory update timed-out", MsgId);
2201 // InventoryRequestData rdata = (InventoryRequestData) sender;
2202 lock (this)
2203 {
2204 this.folders = null;
2205 this.items = null;
2206 this.HaveInventory = false;
2207 this.timeout = true;
2208 Monitor.Pulse(this);
2209 }
2210 }
2211
2212 /// <summary>
2213 /// This is the callback method required by inventory services. The
2214 /// requestor issues an inventory request and then blocks until this
2215 /// method signals the monitor.
2216 /// </summary>
2217
2218 internal void GetUserInventory(ICollection<InventoryFolderImpl> folders, ICollection<InventoryItemBase> items)
2219 {
2220 Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId);
2221 lock (this)
2222 {
2223 if (watchDog.Enabled)
2224 {
2225 this.stopWD();
2226 }
2227 this.folders = folders;
2228 this.items = items;
2229 this.HaveInventory = true;
2230 this.timeout = false;
2231 Monitor.Pulse(this);
2232 }
2233 }
2234 }
2235
2236 #endregion Inventory RequestData extension
2237
2238 /// <summary>
2239 /// This class is used to record and manage the hierarchy
2240 /// constructed from the entity supplied in the request for
2241 /// PUT and POST.
2242 /// </summary>
2243
2244 internal class XmlInventoryCollection : InventoryCollection
2245 {
2246 internal InventoryRequestData rdata;
2247 private Stack<InventoryFolderBase> stk;
2248
2249 internal List<AssetBase> Assets;
2250
2251 internal InventoryItemBase Item;
2252 internal AssetBase Asset;
2253 internal XmlReader xml;
2254
2255 internal /*static*/ const uint DefaultCurrent = 0x7FFFFFFF;
2256 internal /*static*/ const uint DefaultNext = 0x82000;
2257 internal /*static*/ const uint DefaultBase = 0x7FFFFFFF;
2258 internal /*static*/ const uint DefaultEveryOne = 0x0;
2259 internal /*static*/ const uint DefaultGroup = 0x0;
2260
2261 internal uint CurrentPermissions = 0x00;
2262 internal uint NextPermissions = 0x00;
2263 internal uint BasePermissions = 0x00;
2264 internal uint EveryOnePermissions = 0x00;
2265 internal uint GroupPermissions = 0x00;
2266
2267 internal XmlInventoryCollection()
2268 {
2269 Folders = new List<InventoryFolderBase>();
2270 Items = new List<InventoryItemBase>();
2271 Assets = new List<AssetBase>();
2272 }
2273
2274 internal void init(InventoryRequestData p_rdata)
2275 {
2276 rdata = p_rdata;
2277 UserID = rdata.uuid;
2278 stk = new Stack<InventoryFolderBase>();
2279 rdata.initXmlReader();
2280 xml = rdata.reader;
2281 initPermissions();
2282 }
2283
2284 internal void initPermissions()
2285 {
2286 CurrentPermissions = DefaultCurrent;
2287 NextPermissions = DefaultNext;
2288 BasePermissions = DefaultBase;
2289 GroupPermissions = DefaultGroup;
2290 EveryOnePermissions = DefaultEveryOne;
2291 }
2292
2293 internal UUID Parent()
2294 {
2295 if (stk.Count != 0)
2296 {
2297 return stk.Peek().ID;
2298 }
2299 else
2300 {
2301 return UUID.Zero;
2302 }
2303 }
2304
2305 internal void Push(InventoryFolderBase folder)
2306 {
2307 stk.Push(folder);
2308 Folders.Add(folder);
2309 reset();
2310 }
2311
2312 internal void Push(InventoryItemBase item)
2313 {
2314 Item = item;
2315 Items.Add(item);
2316 }
2317
2318 internal void Push(AssetBase asset)
2319 {
2320 Asset = asset;
2321 Assets.Add(asset);
2322 }
2323
2324 internal void Pop()
2325 {
2326 stk.Pop();
2327 reset();
2328 }
2329
2330 internal void reset()
2331 {
2332 Item = null;
2333 Asset = null;
2334 initPermissions();
2335 }
2336
2337 internal void Fail(int code, string addendum)
2338 {
2339 rdata.Fail(code, addendum);
2340 }
2341 }
2342 }
2343}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs
deleted file mode 100644
index 81596a3..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs
+++ /dev/null
@@ -1,246 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenSim.Framework.Servers;
33using OpenSim.Framework.Servers.HttpServer;
34
35namespace OpenSim.ApplicationPlugins.Rest.Inventory
36{
37 public class RestTestServices : IRest
38 {
39 private bool enabled = false;
40 private string qPrefix = "test";
41
42 // A simple constructor is used to handle any once-only
43 // initialization of working classes.
44
45 public RestTestServices()
46 {
47 Rest.Log.InfoFormat("{0} Test services initializing", MsgId);
48 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
49
50 // If a relative path was specified, make it absolute by adding
51 // the standard prefix, e.g. /admin
52
53 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
54 {
55 Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
56 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
57 Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
58 }
59
60 // Load test cases
61
62 loadTests();
63 foreach (ITest test in tests)
64 {
65 test.Initialize();
66 }
67
68 // Register interface
69
70 Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate);
71
72 // Activate
73
74 enabled = true;
75
76 Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId);
77 }
78
79 // Post-construction, pre-enabled initialization opportunity
80 // Not currently exploited.
81
82 public void Initialize()
83 {
84 }
85
86 // Called by the plug-in to halt REST processing. Local processing is
87 // disabled, and control blocks until all current processing has
88 // completed. No new processing will be started
89
90 public void Close()
91 {
92 enabled = false;
93 foreach (ITest test in tests)
94 {
95 test.Close();
96 }
97 Rest.Log.InfoFormat("{0} Test services closing down", MsgId);
98 }
99
100 // Properties
101
102 internal string MsgId
103 {
104 get { return Rest.MsgId; }
105 }
106
107 #region Interface
108
109 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
110 {
111 return new RequestData(request, response, prefix);
112 }
113
114 // Inventory Handler
115
116 private void DoTests(RequestData rdata)
117 {
118 if (!enabled)
119 return;
120
121 // Now that we know this is a serious attempt to
122 // access inventory data, we should find out who
123 // is asking, and make sure they are authorized
124 // to do so. We need to validate the caller's
125 // identity before revealing anything about the
126 // status quo. Authenticate throws an exception
127 // via Fail if no identity information is present.
128 //
129 // With the present HTTP server we can't use the
130 // builtin authentication mechanisms because they
131 // would be enforced for all in-bound requests.
132 // Instead we look at the headers ourselves and
133 // handle authentication directly.
134
135 try
136 {
137 if (!rdata.IsAuthenticated)
138 {
139 rdata.Fail(Rest.HttpStatusCodeNotAuthorized,
140 String.Format("user \"{0}\" could not be authenticated", rdata.userName));
141 }
142 }
143 catch (RestException e)
144 {
145 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
146 {
147 Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
148 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
149 }
150 else
151 {
152 Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
153 Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
154 }
155 throw (e);
156 }
157
158 // Check that a test was specified
159
160 if (rdata.Parameters.Length < 1)
161 {
162 Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId);
163 rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters");
164 }
165
166 // Select the test
167
168 foreach (ITest test in tests)
169 {
170 if (!rdata.handled)
171 test.Execute(rdata);
172 }
173 }
174
175 #endregion Interface
176
177 private static bool testsLoaded = false;
178 private static List<Type> classes = new List<Type>();
179 private static List<ITest> tests = new List<ITest>();
180 private static Type[] parms = new Type[0];
181 private static Object[] args = new Object[0];
182
183 static RestTestServices()
184 {
185 Module[] mods = Assembly.GetExecutingAssembly().GetModules();
186 foreach (Module m in mods)
187 {
188 Type[] types = m.GetTypes();
189 foreach (Type t in types)
190 {
191 try
192 {
193 if (t.GetInterface("ITest") != null)
194 {
195 classes.Add(t);
196 }
197 }
198 catch (Exception e)
199 {
200 Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message);
201 }
202 }
203 }
204 }
205
206 /// <summary>
207 /// This routine loads all of the handlers discovered during
208 /// instance initialization. Each handler is responsible for
209 /// registering itself with this handler.
210 /// I was not able to make this code work in a constructor.
211 /// </summary>
212
213 private void loadTests()
214 {
215 lock (tests)
216 {
217 if (!testsLoaded)
218 {
219
220 ConstructorInfo ci;
221 Object ht;
222
223 foreach (Type t in classes)
224 {
225 try
226 {
227 if (t.GetInterface("ITest") != null)
228 {
229 ci = t.GetConstructor(parms);
230 ht = ci.Invoke(args);
231 tests.Add((ITest)ht);
232 Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t);
233 }
234 }
235 catch (Exception e)
236 {
237 Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message);
238 }
239 }
240 testsLoaded = true;
241 }
242 }
243 }
244
245 }
246}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs
deleted file mode 100644
index eafc154..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs
+++ /dev/null
@@ -1,46 +0,0 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSimulator Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29namespace OpenSim.ApplicationPlugins.Rest.Inventory
30{
31
32 /// <summary>
33 /// This interface represents the boundary between the general purpose
34 /// REST plugin handling, and the functionally specific handlers. The
35 /// handler knows only to initialzie and terminate all such handlers
36 /// that it finds.
37 /// </summary>
38
39 internal interface ITest
40 {
41 void Initialize();
42 void Execute(RequestData rdata);
43 void Close();
44 }
45
46}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs
deleted file mode 100644
index 1c1afd0..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs
+++ /dev/null
@@ -1,204 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests
33{
34 public class Remote : ITest
35 {
36 private static readonly int PARM_TESTID = 0;
37 private static readonly int PARM_COMMAND = 1;
38
39 private static readonly int PARM_MOVE_AVATAR = 2;
40 private static readonly int PARM_MOVE_X = 3;
41 private static readonly int PARM_MOVE_Y = 4;
42 private static readonly int PARM_MOVE_Z = 5;
43
44 private bool enabled = false;
45
46 // No constructor code is required.
47
48 public Remote()
49 {
50 Rest.Log.InfoFormat("{0} Remote services constructor", MsgId);
51 }
52
53 // Post-construction, pre-enabled initialization opportunity
54 // Not currently exploited.
55
56 public void Initialize()
57 {
58 enabled = true;
59 Rest.Log.InfoFormat("{0} Remote services initialized", MsgId);
60 }
61
62 // Called by the plug-in to halt REST processing. Local processing is
63 // disabled, and control blocks until all current processing has
64 // completed. No new processing will be started
65
66 public void Close()
67 {
68 enabled = false;
69 Rest.Log.InfoFormat("{0} Remote services closing down", MsgId);
70 }
71
72 // Properties
73
74 internal string MsgId
75 {
76 get { return Rest.MsgId; }
77 }
78
79 // Remote Handler
80 // Key information of interest here is the Parameters array, each
81 // entry represents an element of the URI, with element zero being
82 // the
83
84 public void Execute(RequestData rdata)
85 {
86 if (!enabled) return;
87
88 // If we can't relate to what's there, leave it for others.
89
90 if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote")
91 return;
92
93 Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId);
94
95 // Remove the prefix and what's left are the parameters. If we don't have
96 // the parameters we need, fail the request. Parameters do NOT include
97 // any supplied query values.
98
99 if (rdata.Parameters.Length > 1)
100 {
101 switch (rdata.Parameters[PARM_COMMAND].ToLower())
102 {
103 case "move" :
104 DoMove(rdata);
105 break;
106 default :
107 DoHelp(rdata);
108 break;
109 }
110 }
111 else
112 {
113 DoHelp(rdata);
114 }
115 }
116
117 private void DoHelp(RequestData rdata)
118 {
119 rdata.body = Help;
120 rdata.Complete();
121 rdata.Respond("Help");
122 }
123
124 private void DoMove(RequestData rdata)
125 {
126 if (rdata.Parameters.Length < 6)
127 {
128 Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId);
129 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided");
130 }
131 else
132 {
133 string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE);
134 ScenePresence presence = null;
135 Scene scene = null;
136
137 if (names.Length != 2)
138 {
139 rdata.Fail(Rest.HttpStatusCodeBadRequest,
140 String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR]));
141 }
142
143 Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}",
144 MsgId, rdata.Parameters[0], names[0], names[1]);
145
146 // The first parameter should be an avatar name, look for the
147 // avatar in the known regions first.
148
149 Rest.main.SceneManager.ForEachScene(delegate(Scene s)
150 {
151 s.ForEachRootScenePresence(delegate(ScenePresence sp)
152 {
153 if (sp.Firstname == names[0] && sp.Lastname == names[1])
154 {
155 scene = s;
156 presence = sp;
157 }
158 });
159 });
160
161 if (presence != null)
162 {
163 Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}",
164 MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName);
165
166 try
167 {
168 float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]);
169 float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]);
170 float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]);
171 Vector3 vector = new Vector3(x, y, z);
172 presence.MoveToTarget(vector, false, false);
173 }
174 catch (Exception e)
175 {
176 rdata.Fail(Rest.HttpStatusCodeBadRequest,
177 String.Format("invalid parameters: {0}", e.Message));
178 }
179 }
180 else
181 {
182 rdata.Fail(Rest.HttpStatusCodeBadRequest,
183 String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR]));
184 }
185
186 rdata.Complete();
187 rdata.Respond("OK");
188 }
189 }
190
191 private static readonly string Help =
192 "<html>"
193 + "<head><title>Remote Command Usage</title></head>"
194 + "<body>"
195 + "<p>Supported commands are:</p>"
196 + "<dl>"
197 + "<dt>move/avatar-name/x/y/z</dt>"
198 + "<dd>moves the specified avatar to another location</dd>"
199 + "</dl>"
200 + "</body>"
201 + "</html>"
202 ;
203 }
204}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs
deleted file mode 100644
index d99ba57..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs
+++ /dev/null
@@ -1,228 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Xml.Serialization;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Framework.Servers;
34using OpenSim.Framework.Servers.HttpServer;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.ApplicationPlugins.Rest.Regions
39{
40 public partial class RestRegionPlugin : RestPlugin
41 {
42 #region GET methods
43 public string GetHandler(string request, string path, string param,
44 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
45 {
46 // foreach (string h in httpRequest.Headers.AllKeys)
47 // foreach (string v in httpRequest.Headers.GetValues(h))
48 // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
49
50 MsgID = RequestID;
51 m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
52
53 try
54 {
55 // param empty: regions list
56 if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse);
57
58 // param not empty: specific region
59 return GetHandlerRegion(httpResponse, param);
60 }
61 catch (Exception e)
62 {
63 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
64 }
65 }
66
67 public string GetHandlerRegions(IOSHttpResponse httpResponse)
68 {
69 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
70
71 rxw.WriteStartElement(String.Empty, "regions", String.Empty);
72 foreach (Scene s in App.SceneManager.Scenes)
73 {
74 rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
75 rxw.WriteString(s.RegionInfo.RegionID.ToString());
76 rxw.WriteEndElement();
77 }
78 rxw.WriteEndElement();
79
80 return rxw.ToString();
81 }
82
83 protected string ShortRegionInfo(string key, string value)
84 {
85 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
86
87 if (String.IsNullOrEmpty(value) ||
88 String.IsNullOrEmpty(key)) return null;
89
90 rxw.WriteStartElement(String.Empty, "region", String.Empty);
91 rxw.WriteStartElement(String.Empty, key, String.Empty);
92 rxw.WriteString(value);
93 rxw.WriteEndDocument();
94
95 return rxw.ToString();
96 }
97
98 public string GetHandlerRegion(IOSHttpResponse httpResponse, string param)
99 {
100 // be resilient and don't get confused by a terminating '/'
101 param = param.TrimEnd(new char[]{'/'});
102 string[] comps = param.Split('/');
103 UUID regionID = (UUID)comps[0];
104
105 m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString());
106
107 if (UUID.Zero == regionID) throw new Exception("missing region ID");
108
109 Scene scene = null;
110 App.SceneManager.TryGetScene(regionID, out scene);
111 if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
112 "GET", "cannot find region {0}", regionID.ToString());
113
114 RegionDetails details = new RegionDetails(scene.RegionInfo);
115
116 // m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length);
117 // for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]);
118
119 if (1 == comps.Length)
120 {
121 // complete region details requested
122 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
123 XmlSerializer xs = new XmlSerializer(typeof(RegionDetails));
124 xs.Serialize(rxw, details, _xmlNs);
125 return rxw.ToString();
126 }
127
128 if (2 == comps.Length)
129 {
130 string resp = ShortRegionInfo(comps[1], details[comps[1]]);
131 if (null != resp) return resp;
132
133 // m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]);
134
135 // check for {terrain,stats,prims}
136 switch (comps[1].ToLower())
137 {
138 case "terrain":
139 return RegionTerrain(httpResponse, scene);
140
141 case "stats":
142 return RegionStats(httpResponse, scene);
143
144 case "prims":
145 return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero);
146 }
147 }
148
149 if (3 == comps.Length)
150 {
151 switch (comps[1].ToLower())
152 {
153 case "prims":
154 string[] subregion = comps[2].Split(',');
155 if (subregion.Length == 6)
156 {
157 Vector3 min, max;
158 try
159 {
160 min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo));
161 max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo));
162 }
163 catch (Exception)
164 {
165 return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
166 "GET", "invalid subregion parameter");
167 }
168 return RegionPrims(httpResponse, scene, min, max);
169 }
170 else
171 {
172 return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
173 "GET", "invalid subregion parameter");
174 }
175 }
176 }
177
178 return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
179 "GET", "too many parameters {0}", param);
180 }
181 #endregion GET methods
182
183 protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene)
184 {
185 httpResponse.SendChunked = true;
186 httpResponse.ContentType = "text/xml";
187
188 return scene.Heightmap.SaveToXmlString();
189 //return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented,
190 // "GET", "terrain not implemented");
191 }
192
193 protected string RegionStats(IOSHttpResponse httpResponse, Scene scene)
194 {
195 int users = scene.GetRootAgentCount();
196 int objects = scene.Entities.Count - users;
197
198 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
199
200 rxw.WriteStartElement(String.Empty, "region", String.Empty);
201 rxw.WriteStartElement(String.Empty, "stats", String.Empty);
202
203 rxw.WriteStartElement(String.Empty, "users", String.Empty);
204 rxw.WriteString(users.ToString());
205 rxw.WriteEndElement();
206
207 rxw.WriteStartElement(String.Empty, "objects", String.Empty);
208 rxw.WriteString(objects.ToString());
209 rxw.WriteEndElement();
210
211 rxw.WriteEndDocument();
212
213 return rxw.ToString();
214 }
215
216 protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max)
217 {
218 httpResponse.SendChunked = true;
219 httpResponse.ContentType = "text/xml";
220
221 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
222 if (serialiser != null)
223 serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max);
224
225 return "";
226 }
227 }
228}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs
deleted file mode 100644
index 468faea..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs
+++ /dev/null
@@ -1,136 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Xml.Serialization;
31using OpenMetaverse;
32using OpenSim.Framework.Servers;
33using OpenSim.Framework.Servers.HttpServer;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.ApplicationPlugins.Rest.Regions
38{
39 public partial class RestRegionPlugin : RestPlugin
40 {
41 #region GET methods
42 public string GetRegionInfoHandler(string request, string path, string param,
43 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
44 {
45 // foreach (string h in httpRequest.Headers.AllKeys)
46 // foreach (string v in httpRequest.Headers.GetValues(h))
47 // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
48
49 MsgID = RequestID;
50 m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
51
52 try
53 {
54 // param empty: regions list
55 // if (String.IsNullOrEmpty(param))
56 return GetRegionInfoHandlerRegions(httpResponse);
57
58 // // param not empty: specific region
59 // return GetRegionInfoHandlerRegion(httpResponse, param);
60 }
61 catch (Exception e)
62 {
63 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
64 }
65 }
66
67 public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse)
68 {
69 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
70
71 // regions info
72 rxw.WriteStartElement(String.Empty, "regions", String.Empty);
73 {
74 // regions info: number of regions
75 rxw.WriteStartAttribute(String.Empty, "number", String.Empty);
76 rxw.WriteValue(App.SceneManager.Scenes.Count);
77 rxw.WriteEndAttribute();
78
79 // regions info: max number of regions
80 rxw.WriteStartAttribute(String.Empty, "max", String.Empty);
81 if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null)
82 {
83 rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1));
84 }
85 else
86 {
87 rxw.WriteValue(-1);
88 }
89 rxw.WriteEndAttribute();
90
91 // regions info: region
92 foreach (Scene s in App.SceneManager.Scenes)
93 {
94 rxw.WriteStartElement(String.Empty, "region", String.Empty);
95
96 rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty);
97 rxw.WriteString(s.RegionInfo.RegionID.ToString());
98 rxw.WriteEndAttribute();
99
100 rxw.WriteStartAttribute(String.Empty, "name", String.Empty);
101 rxw.WriteString(s.RegionInfo.RegionName);
102 rxw.WriteEndAttribute();
103
104 rxw.WriteStartAttribute(String.Empty, "x", String.Empty);
105 rxw.WriteValue(s.RegionInfo.RegionLocX);
106 rxw.WriteEndAttribute();
107
108 rxw.WriteStartAttribute(String.Empty, "y", String.Empty);
109 rxw.WriteValue(s.RegionInfo.RegionLocY);
110 rxw.WriteEndAttribute();
111
112 rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty);
113 rxw.WriteString(s.RegionInfo.ExternalHostName);
114 rxw.WriteEndAttribute();
115
116 rxw.WriteStartAttribute(String.Empty, "ip", String.Empty);
117 rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString());
118 rxw.WriteEndAttribute();
119
120 int users = s.GetRootAgentCount();
121 rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty);
122 rxw.WriteValue(users);
123 rxw.WriteEndAttribute();
124
125 rxw.WriteStartAttribute(String.Empty, "objects", String.Empty);
126 rxw.WriteValue(s.Entities.Count - users);
127 rxw.WriteEndAttribute();
128
129 rxw.WriteEndElement();
130 }
131 }
132 return rxw.ToString();
133 }
134 #endregion GET methods
135 }
136}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs
deleted file mode 100644
index f666f45..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs
+++ /dev/null
@@ -1,122 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using OpenMetaverse;
31using OpenSim.Framework.Servers;
32using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.ApplicationPlugins.Rest.Regions
37{
38 public partial class RestRegionPlugin : RestPlugin
39 {
40 #region POST methods
41
42 public string PostHandler(string request, string path, string param,
43 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
44 {
45 // foreach (string h in httpRequest.Headers.AllKeys)
46 // foreach (string v in httpRequest.Headers.GetValues(h))
47 // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
48
49 MsgID = RequestID;
50 m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param);
51
52 try
53 {
54 // param empty: new region post
55 if (!IsGod(httpRequest))
56 // XXX: this needs to be turned into a FailureUnauthorized(...)
57 return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized,
58 "GET", "you are not god");
59
60 if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse);
61
62 // Parse region ID and other parameters
63 param = param.TrimEnd(new char[] {'/'});
64 string[] comps = param.Split('/');
65 UUID regionID = (UUID) comps[0];
66
67 m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString());
68 if (UUID.Zero == regionID) throw new Exception("missing region ID");
69
70 Scene scene = null;
71 App.SceneManager.TryGetScene(regionID, out scene);
72 if (null == scene)
73 return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
74 "POST", "cannot find region {0}", regionID.ToString());
75
76 if (2 == comps.Length)
77 {
78 // check for {prims}
79 switch (comps[1].ToLower())
80 {
81 case "prims":
82 return LoadPrims(request, httpRequest, httpResponse, scene);
83 }
84 }
85
86 return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
87 "POST", "url {0} not supported", param);
88 }
89 catch (Exception e)
90 {
91 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e);
92 }
93 }
94
95 public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response)
96 {
97 RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
98
99 rxw.WriteStartElement(String.Empty, "regions", String.Empty);
100 foreach (Scene s in App.SceneManager.Scenes)
101 {
102 rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
103 rxw.WriteString(s.RegionInfo.RegionID.ToString());
104 rxw.WriteEndElement();
105 }
106 rxw.WriteEndElement();
107
108 return rxw.ToString();
109 }
110
111 public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene)
112 {
113 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
114 if (serialiser != null)
115 serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true);
116
117 return "";
118 }
119
120 #endregion POST methods
121 }
122}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs
deleted file mode 100644
index 5e76009..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Xml.Serialization;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.ApplicationPlugins.Rest.Regions
34{
35 [XmlRoot(ElementName="region", IsNullable = false)]
36 public class RegionDetails
37 {
38 public string region_name;
39 public string region_id;
40 public uint region_x;
41 public uint region_y;
42 public string region_owner;
43 public string region_owner_id;
44 public uint region_http_port;
45 public uint region_port;
46 public string region_server_uri;
47 public string region_external_hostname;
48
49 public RegionDetails()
50 {
51 }
52
53 public RegionDetails(RegionInfo regInfo)
54 {
55 region_name = regInfo.RegionName;
56 region_id = regInfo.RegionID.ToString();
57 region_x = regInfo.RegionLocX;
58 region_y = regInfo.RegionLocY;
59 region_owner_id = regInfo.EstateSettings.EstateOwner.ToString();
60 region_http_port = regInfo.HttpPort;
61 region_server_uri = regInfo.ServerURI;
62 region_external_hostname = regInfo.ExternalHostName;
63
64 Uri uri = new Uri(region_server_uri);
65 region_port = (uint)uri.Port;
66 }
67
68 public string this[string idx]
69 {
70 get
71 {
72 switch (idx.ToLower())
73 {
74 case "name":
75 return region_name;
76 case "id":
77 return region_id;
78 case "location":
79 return String.Format("<x>{0}</x><y>{1}</y>", region_x, region_y);
80 case "owner":
81 return region_owner;
82 case "owner_id":
83 return region_owner_id;
84 case "http_port":
85 return region_http_port.ToString();
86 case "server_uri":
87 return region_server_uri;
88 case "external_hostname":
89 case "hostname":
90 return region_external_hostname;
91
92 default:
93 return null;
94 }
95 }
96 }
97 }
98}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml b/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml
deleted file mode 100644
index 94eca48..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml
+++ /dev/null
@@ -1,11 +0,0 @@
1<Addin id="OpenSim.ApplicationPlugins.Rest.Regions" version="0.1">
2 <Runtime>
3 <Import assembly="OpenSim.ApplicationPlugins.Rest.Regions.dll"/>
4 </Runtime>
5 <Dependencies>
6 <Addin id="OpenSim" version="0.5" />
7 </Dependencies>
8 <Extension path = "/OpenSim/Startup">
9 <Plugin id="RestRegions" type="OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin" />
10 </Extension>
11</Addin>
diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
deleted file mode 100644
index a2425b5..0000000
--- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
+++ /dev/null
@@ -1,417 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using log4net;
34using Nini.Config;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers;
38using OpenSim.Framework.Servers.HttpServer;
39
40namespace OpenSim.ApplicationPlugins.Rest
41{
42 public abstract class RestPlugin : IApplicationPlugin
43 {
44 #region properties
45
46 protected static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private IConfig _config; // Configuration source: Rest Plugins
50 private IConfig _pluginConfig; // Configuration source: Plugin specific
51 private OpenSimBase _app; // The 'server'
52 private BaseHttpServer _httpd; // The server's RPC interface
53 private string _prefix; // URL prefix below
54 // which all REST URLs
55 // are living
56 // private StringWriter _sw = null;
57 // private RestXmlWriter _xw = null;
58
59 private string _godkey;
60 private int _reqk;
61
62 [ThreadStatic]
63 private static string _threadRequestID = String.Empty;
64
65 /// <summary>
66 /// Return an ever increasing request ID for logging
67 /// </summary>
68 protected string RequestID
69 {
70 get { return _reqk++.ToString(); }
71 set { _reqk = Convert.ToInt32(value); }
72 }
73
74 /// <summary>
75 /// Thread-constant message IDs for logging.
76 /// </summary>
77 protected string MsgID
78 {
79 get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); }
80 set { _threadRequestID = value; }
81 }
82
83 /// <summary>
84 /// Returns true if Rest Plugins are enabled.
85 /// </summary>
86 public bool PluginsAreEnabled
87 {
88 get { return null != _config; }
89 }
90
91 /// <summary>
92 /// Returns true if specific Rest Plugin is enabled.
93 /// </summary>
94 public bool IsEnabled
95 {
96 get
97 {
98 return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false);
99 }
100 }
101
102 /// <summary>
103 /// OpenSimMain application
104 /// </summary>
105 public OpenSimBase App
106 {
107 get { return _app; }
108 }
109
110 /// <summary>
111 /// RPC server
112 /// </summary>
113 public BaseHttpServer HttpServer
114 {
115 get { return _httpd; }
116 }
117
118 /// <summary>
119 /// URL prefix to use for all REST handlers
120 /// </summary>
121 public string Prefix
122 {
123 get { return _prefix; }
124 }
125
126 /// <summary>
127 /// Access to GOD password string
128 /// </summary>
129 protected string GodKey
130 {
131 get { return _godkey; }
132 }
133
134 /// <summary>
135 /// Configuration of the plugin
136 /// </summary>
137 public IConfig Config
138 {
139 get { return _pluginConfig; }
140 }
141
142 /// <summary>
143 /// Name of the plugin
144 /// </summary>
145 public abstract string Name { get; }
146
147 /// <summary>
148 /// Return the config section name
149 /// </summary>
150 public abstract string ConfigName { get; }
151
152 // public XmlTextWriter XmlWriter
153 // {
154 // get
155 // {
156 // if (null == _xw)
157 // {
158 // _sw = new StringWriter();
159 // _xw = new RestXmlWriter(_sw);
160 // _xw.Formatting = Formatting.Indented;
161 // }
162 // return _xw;
163 // }
164 // }
165
166 // public string XmlWriterResult
167 // {
168 // get
169 // {
170 // _xw.Flush();
171 // _xw.Close();
172 // _xw = null;
173
174 // return _sw.ToString();
175 // }
176 // }
177
178 #endregion properties
179
180 #region methods
181
182 // TODO: required by IPlugin, but likely not at all right
183 private string m_version = "0.0";
184
185 public string Version
186 {
187 get { return m_version; }
188 }
189
190 public void Initialise()
191 {
192 m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!");
193 throw new PluginNotInitialisedException(Name);
194 }
195
196 /// <summary>
197 /// This method is called by OpenSimMain immediately after loading the
198 /// plugin and after basic server setup, but before running any server commands.
199 /// </summary>
200 /// <remarks>
201 /// Note that entries MUST be added to the active configuration files before
202 /// the plugin can be enabled.
203 /// </remarks>
204 public virtual void Initialise(OpenSimBase openSim)
205 {
206 RequestID = "0";
207 MsgID = RequestID;
208
209 try
210 {
211 if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null)
212 {
213 m_log.WarnFormat("{0} Rest Plugins not configured", MsgID);
214 return;
215 }
216
217 if (!_config.GetBoolean("enabled", false))
218 {
219 //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
220 return;
221 }
222
223 _app = openSim;
224 _httpd = openSim.HttpServer;
225
226 // Retrieve GOD key value, if any.
227 _godkey = _config.GetString("god_key", String.Empty);
228
229 // Retrive prefix if any.
230 _prefix = _config.GetString("prefix", "/admin");
231
232 // Get plugin specific config
233 _pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName];
234
235 m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID);
236 }
237 catch (Exception e)
238 {
239 // we can safely ignore this, as it just means that
240 // the key lookup in Configs failed, which signals to
241 // us that noone is interested in our services...they
242 // don't know what they are missing out on...
243 // NOTE: Under the present OpenSimulator implementation it is
244 // not possible for the openSimulator pointer to be null. However
245 // were the implementation to be changed, this could
246 // result in a silent initialization failure. Harmless
247 // except for lack of function and lack of any
248 // diagnostic indication as to why. The same is true if
249 // the HTTP server reference is bad.
250 // We should at least issue a message...
251 m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
252 m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
253 }
254 }
255
256 public virtual void PostInitialise()
257 {
258 }
259
260 private List<RestStreamHandler> _handlers = new List<RestStreamHandler>();
261 private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>();
262
263 /// <summary>
264 /// Add a REST stream handler to the underlying HTTP server.
265 /// </summary>
266 /// <param name="httpMethod">GET/PUT/POST/DELETE or
267 /// similar</param>
268 /// <param name="path">URL prefix</param>
269 /// <param name="method">RestMethod handler doing the actual work</param>
270 public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method)
271 {
272 if (!IsEnabled) return;
273
274 if (!path.StartsWith(_prefix))
275 {
276 path = String.Format("{0}{1}", _prefix, path);
277 }
278
279 RestStreamHandler h = new RestStreamHandler(httpMethod, path, method);
280 _httpd.AddStreamHandler(h);
281 _handlers.Add(h);
282
283 m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path);
284 }
285
286 /// <summary>
287 /// Add a powerful Agent handler to the underlying HTTP
288 /// server.
289 /// </summary>
290 /// <param name="agentName">name of agent handler</param>
291 /// <param name="handler">agent handler method</param>
292 /// <returns>false when the plugin is disabled or the agent
293 /// handler could not be added. Any generated exceptions are
294 /// allowed to drop through to the caller, i.e. ArgumentException.
295 /// </returns>
296 public bool AddAgentHandler(string agentName, IHttpAgentHandler handler)
297 {
298 if (!IsEnabled) return false;
299 _agents.Add(agentName, handler);
300// return _httpd.AddAgentHandler(agentName, handler);
301
302 return false;
303 }
304
305 /// <summary>
306 /// Remove a powerful Agent handler from the underlying HTTP
307 /// server.
308 /// </summary>
309 /// <param name="agentName">name of agent handler</param>
310 /// <param name="handler">agent handler method</param>
311 /// <returns>false when the plugin is disabled or the agent
312 /// handler could not be removed. Any generated exceptions are
313 /// allowed to drop through to the caller, i.e. KeyNotFound.
314 /// </returns>
315 public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler)
316 {
317 if (!IsEnabled) return false;
318 if (_agents[agentName] == handler)
319 {
320 _agents.Remove(agentName);
321// return _httpd.RemoveAgentHandler(agentName, handler);
322 }
323 return false;
324 }
325
326 /// <summary>
327 /// Check whether the HTTP request came from god; that is, is
328 /// the god_key as configured in the config section supplied
329 /// via X-OpenSim-Godkey?
330 /// </summary>
331 /// <param name="request">HTTP request header</param>
332 /// <returns>true when the HTTP request came from god.</returns>
333 protected bool IsGod(IOSHttpRequest request)
334 {
335 string[] keys = request.Headers.GetValues("X-OpenSim-Godkey");
336 if (null == keys) return false;
337
338 // we take the last key supplied
339 return keys[keys.Length - 1] == _godkey;
340 }
341
342 /// <summary>
343 /// Checks wether the X-OpenSim-Password value provided in the
344 /// HTTP header is indeed the password on file for the avatar
345 /// specified by the UUID
346 /// </summary>
347 protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid)
348 {
349 // XXX under construction
350 return false;
351 }
352
353 /// <summary>
354 /// Clean up and remove all handlers that were added earlier.
355 /// </summary>
356 public virtual void Close()
357 {
358 foreach (RestStreamHandler h in _handlers)
359 {
360 _httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
361 }
362 _handlers = null;
363// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
364// {
365// _httpd.RemoveAgentHandler(h.Key, h.Value);
366// }
367 _agents = null;
368 }
369
370 public virtual void Dispose()
371 {
372 Close();
373 }
374
375 /// <summary>
376 /// Return a failure message.
377 /// </summary>
378 /// <param name="method">origin of the failure message</param>
379 /// <param name="message">failure message</param>
380 /// <remarks>This should probably set a return code as
381 /// well. (?)</remarks>
382 protected string Failure(IOSHttpResponse response, OSHttpStatusCode status,
383 string method, string format, params string[] msg)
384 {
385 string m = String.Format(format, msg);
386
387 response.StatusCode = (int) status;
388 response.StatusDescription = m;
389
390 m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m);
391 return String.Format("<error>{0}</error>", m);
392 }
393
394 /// <summary>
395 /// Return a failure message.
396 /// </summary>
397 /// <param name="method">origin of the failure message</param>
398 /// <param name="e">exception causing the failure message</param>
399 /// <remarks>This should probably set a return code as
400 /// well. (?)</remarks>
401 public string Failure(IOSHttpResponse response, OSHttpStatusCode status,
402 string method, Exception e)
403 {
404 string m = String.Format("exception occurred: {0}", e.Message);
405
406 response.StatusCode = (int) status;
407 response.StatusDescription = m;
408
409 m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString());
410 m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message);
411
412 return String.Format("<error>{0}</error>", e.Message);
413 }
414
415 #endregion methods
416 }
417}
diff --git a/OpenSim/ApplicationPlugins/Rest/rest.xsd b/OpenSim/ApplicationPlugins/Rest/rest.xsd
deleted file mode 100644
index 4dc0ae4..0000000
--- a/OpenSim/ApplicationPlugins/Rest/rest.xsd
+++ /dev/null
@@ -1,276 +0,0 @@
1<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
3 <xsd:annotation>
4 <xsd:documentation xml:lang="en">
5 Open Simulator Export/Import XML schema
6 August 2008
7 </xsd:documentation>
8 </xsd:annotation>
9
10 <!-- WARNING!!!
11 This is currently a draft, it does not reflect
12 what is exported, nor what will be understood
13 on import. It is included as a working document
14 and this comment will be removed at such time as
15 the schema corresponds to reality.
16 -->
17
18 <!--
19 REST-related information
20 Inventory data is always framed by an
21 inventory element. Consists of zero or
22 more elements representing either folders
23 or items within those folders. The inventory
24 element represents the "real" root folder.
25 -->
26
27 <xsd:element name="inventory" type="inventory_ct" />
28
29 <!--
30 The inventory complex type is just an arbitrary
31 sequence of folders and items. In reality it is
32 typically just folders. Both item and folder
33 have corresponding complex types. It is distinct
34 from folders insofar as it has no other defining
35 attributes.
36 -->
37
38 <xsd:complexType name="inventory_ct">
39 <xsd:element name="folder" type="folder_ct" maxOccurs="unbounded"/>
40 <xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
41 </xsd:complexType>
42
43 <xsd:complexType name="folder_ct">
44 <xsd:attribute name="UUID" type="uuid_st" />
45 <xsd:attribute name="name" type="name_st" />
46 <xsd:attribute name="type" type="folder_type_st" />
47 <xsd:attribute name="description" type="xsd:string" /> <!-- added -->
48 <xsd:attribute name="version" type="unsignedShort" />
49 <xsd:attribute name="owner" type="uuid_st" />
50
51 <xsd:attribute name="creator" type="uuid_st" /> <!-- added -->
52 <xsd:attribute name="creationdate" type="date_st" /> <!-- added -->
53
54 <xsd:attribute name="parent" type="uuid_st" />
55
56 <xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" /> <!-- added -->
57 <xsd:element name="folder" type="folder_ct" maxOccurs="unbounded" />
58 <xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
59 </xsd:complexType>
60
61 <xsd:complexType name="item_ct">
62 <xsd:attribute name="UUID" type="uuid_st" />
63 <xsd:attribute name="name" type="name_st" />
64 <xsd:attribute name="type" type="inventory_type_st" />
65 <xsd:attribute name="description" type="xsd:string" />
66 <xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
67 <xsd:attribute name="owner" type="uuid_st" />
68
69 <xsd:attribute name="creator" type="uuid_st" />
70 <xsd:attribute name="creationdate" type="date_st" />
71
72 <xsd:attribute name="folder" type="uuid_st" />
73 <xsd:attribute name="groupid" type="uuid_st" />
74 <xsd:attribute name="groupowned" type="xsd:boolean" />
75 <xsd:attribute name="saletype" type="sale_st" />
76 <xsd:attribute name="saleprice" type="xsd:decimal" />
77
78 <xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" />
79 </xsd:complexType>
80
81 <xsd:complexType name="asset_ct">
82 <xsd:attribute name="UUID" type="uuid_st" />
83 <xsd:attribute name="name" type="name_st" />
84 <xsd:attribute name="type" type="asset_type_st" />
85 <xsd:attribute name="description" type="xsd:string" />
86 <xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
87 <xsd:attribute name="owner" type="uuid_st" />
88
89 <xsd:attribute name="creator" type="uuid_st" />
90 <xsd:attribute name="creationdate" type="date_st" />
91
92 <xsd:attribute name="temporary" type="xsd:boolean" />
93 <xsd:attribute name="local" type="xsd:boolean" />
94 <xsd:attribute name="inline" type="xsd:boolean" />
95 </xsd:complexType>
96
97 <!-- Constrained Simple Data types -->
98
99 <!--
100 We need to specify name as a simple type because on
101 some platforms it is constrained by a certain length
102 limitation. For completeness we indicate that whitespace
103 should be preserved exactly as specified.
104 -->
105
106 <xsd:simpleType name="name_st">
107 <xsd:restriction base="xsd:string">
108 <whiteSpace value="preserve" />
109 <minLength value="0" />
110 <maxLength value="64" />
111 </xsd:restriction>
112 </xsd:simpleType>
113
114 <!--
115 Type information in the folder is meant to indicate
116 the preferred asset type for this folder. As such, that
117 currently corresponds to the type values allowed for
118 assets, however that is not mandated, so for
119 now at least I'll represent this as a distinct
120 enumeration.
121 This seems inappropriate; it seems like the folder's
122 content should reflect the InventoryType classifications
123 rather than the asset types.
124 -->
125
126 <xsd:simpleType name="folder_type_st">
127 <xsd:restriction base="xsd:string">
128 <xsd:enumeration value="Texture" />
129 <xsd:enumeration value="Sound" />
130 <xsd:enumeration value="CallingCard" />
131 <xsd:enumeration value="Landmark" />
132 <xsd:enumeration value="Script" />
133 <xsd:enumeration value="Clothing" />
134 <xsd:enumeration value="Object" />
135 <xsd:enumeration value="Notecard" />
136 <xsd:enumeration value="LSLText" />
137 <xsd:enumeration value="LSLByteCode" />
138 <xsd:enumeration value="TextureTGA" />
139 <xsd:enumeration value="BodyPart" />
140 <xsd:enumeration value="SoundWAV" />
141 <xsd:enumeration value="ImageTGA" />
142 <xsd:enumeration value="ImageJPEG" />
143 <xsd:enumeration value="Animation" />
144 <xsd:enumeration value="Gesture" />
145 <xsd:enumeration value="Simstate" />
146 <xsd:enumeration value="Unknown" />
147 <xsd:enumeration value="LostAndFoundFolder" />
148 <xsd:enumeration value="SnapshotFolder" />
149 <xsd:enumeration value="TrashFolder" />
150 <xsd:enumeration value="Folder" />
151 <xsd:enumeration value="RootFolder" />
152 </xsd:restriction>
153 </xsd:simpleType>
154
155 <!--
156 Inventory item type designates an asset class, rather
157 than a specific asset type. For example, "SnapShot"
158 might include a number of asset types such as JPEG,
159 TGA, etc.. This is not a consistent interpretation,
160 classifications such as LostAndFound are meta-types
161 relative to asset classes.
162
163 These types should be abstract and not be tied to a
164 specific platform. A world's import facility should be
165 responsible for mapping these to meaningful internal
166 representations.
167
168 These types were based on information in:
169 libsecondlife/InventoryManager.cs
170 -->
171
172 <xsd:simpleType name="inventory_type_st">
173 <xsd:restriction base="xsd:string">
174 <xsd:enumeration value="Texture" />
175 <xsd:enumeration value="Sound" />
176 <xsd:enumeration value="CallingCard" />
177 <xsd:enumeration value="Landmark" />
178 <xsd:enumeration value="Script" />
179 <xsd:enumeration value="Clothing" />
180 <xsd:enumeration value="Object" />
181 <xsd:enumeration value="Notecard" />
182 <xsd:enumeration value="LSL" />
183 <xsd:enumeration value="LSLBytecode" />
184 <xsd:enumeration value="TextureTGA" />
185 <xsd:enumeration value="BodyPart" />
186 <xsd:enumeration value="Snapshot" />
187 <xsd:enumeration value="Attachment" />
188 <xsd:enumeration value="Wearable" />
189 <xsd:enumeration value="Animation" />
190 <xsd:enumeration value="Gesture" />
191 <xsd:enumeration value="Folder" />
192 <xsd:enumeration value="Unknown" />
193 <xsd:enumeration value="LostAndFound" />
194 <xsd:enumeration value="Trash" />
195 <xsd:enumeration value="Root" />
196 </xsd:restriction>
197 </xsd:simpleType>
198
199 <!--
200 The asset types seem to be even more disarrayed than
201 the inventory types. It seems to be little more than
202 a reiteration of the inventory type information,
203 which adds little or nothing to the overall data
204 model.
205
206 Of course, given that these are drawn from the
207 libsecondlife definitions, we aren't at liberty to
208 simply redefine them in place. But the XML definitions
209 here could be made more useful.
210
211 These types were based on information in:
212 libsecondlife/AssetManager.cs
213 -->
214
215 <xsd:simpleType name="asset_type_st">
216 <xsd:restriction base="xsd:string">
217 <xsd:enumeration value="Texture" />
218 <xsd:enumeration value="Sound" />
219 <xsd:enumeration value="CallingCard" />
220 <xsd:enumeration value="Landmark" />
221 <xsd:enumeration value="Script" />
222 <xsd:enumeration value="Clothing" />
223 <xsd:enumeration value="Object" />
224 <xsd:enumeration value="Notecard" />
225 <xsd:enumeration value="LSLText" />
226 <xsd:enumeration value="LSLByteCode" />
227 <xsd:enumeration value="TextureTGA" />
228 <xsd:enumeration value="BodyPart" />
229 <xsd:enumeration value="SoundWAV" />
230 <xsd:enumeration value="ImageTGA" />
231 <xsd:enumeration value="ImageJPEG" />
232 <xsd:enumeration value="Animation" />
233 <xsd:enumeration value="Gesture" />
234 <xsd:enumeration value="Simstate" />
235 <xsd:enumeration value="Unknown" />
236 <xsd:enumeration value="LostAndFoundFolder" />
237 <xsd:enumeration value="SnapshotFolder" />
238 <xsd:enumeration value="TrashFolder" />
239 <xsd:enumeration value="Folder" />
240 <xsd:enumeration value="RootFolder" />
241 </xsd:restriction>
242 </xsd:simpleType>
243
244 <!-- This is describing the apparent form of a UUID. If
245 we ever want a more metaphysical definition we'll
246 need to add to it.
247 -->
248
249 <xsd:simpleType name="uuid_st">
250 <xsd:restriction base="xsd:string">
251 <xsd:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/>
252 </xsd:restriction>
253 </xsd:simpleType>
254
255 <!-- This constrains the date representation. Currently
256 it is simply an integer representing the elapsed
257 ?? since ??.
258 -->
259
260 <xsd:simpleType name="date_st">
261 <xsd:restriction base="xsd:positiveInteger">
262 </xsd:restriction>
263 </xsd:simpleType>
264
265 <!-- This constrains the representation of sale price.
266 Currently it is a simple decimal with no unit
267 specified.
268 Issues: interoperability.
269 -->
270
271 <xsd:simpleType name="sale_st">
272 <xsd:restriction base="xsd:decimal">
273 </xsd:restriction>
274 </xsd:simpleType>
275
276</xsd:schema>
diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index bc6f6f9..241fef3 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO; 31using System.IO;
32using System.Reflection; 32using System.Reflection;
33using System.Threading;
33using log4net; 34using log4net;
34using Nini.Config; 35using Nini.Config;
35using OpenMetaverse; 36using OpenMetaverse;
@@ -68,6 +69,7 @@ namespace OpenSim.Framework.Capabilities
68 private IHttpServer m_httpListener; 69 private IHttpServer m_httpListener;
69 private UUID m_agentID; 70 private UUID m_agentID;
70 private string m_regionName; 71 private string m_regionName;
72 private ManualResetEvent m_capsActive = new ManualResetEvent(false);
71 73
72 public UUID AgentID 74 public UUID AgentID
73 { 75 {
@@ -171,5 +173,16 @@ namespace OpenSim.Framework.Capabilities
171 } 173 }
172 } 174 }
173 } 175 }
176
177 public void Activate()
178 {
179 m_capsActive.Set();
180 }
181
182 public bool WaitForActivation()
183 {
184 // Wait for 30s. If that elapses, return false and run without caps
185 return m_capsActive.WaitOne(30000);
186 }
174 } 187 }
175} 188}
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index 68686c5..aa6203b 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -240,6 +240,11 @@ namespace OpenSim.Capabilities.Handlers
240 } 240 }
241 else 241 else
242 { 242 {
243 // Handle the case where no second range value was given. This is equivalent to requesting
244 // the rest of the entity.
245 if (end == -1)
246 end = int.MaxValue;
247
243 end = Utils.Clamp(end, 0, texture.Data.Length - 1); 248 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
244 start = Utils.Clamp(start, 0, end); 249 start = Utils.Clamp(start, 0, end);
245 int len = end - start + 1; 250 int len = end - start + 1;
@@ -298,15 +303,43 @@ namespace OpenSim.Capabilities.Handlers
298// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); 303// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
299 } 304 }
300 305
306 /// <summary>
307 /// Parse a range header.
308 /// </summary>
309 /// <remarks>
310 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
311 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
312 /// Where there is no value, -1 is returned.
313 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
314 /// for start.</remarks>
315 /// <returns></returns>
316 /// <param name='header'></param>
317 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
318 /// <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>
301 private bool TryParseRange(string header, out int start, out int end) 319 private bool TryParseRange(string header, out int start, out int end)
302 { 320 {
321 start = end = 0;
322
303 if (header.StartsWith("bytes=")) 323 if (header.StartsWith("bytes="))
304 { 324 {
305 string[] rangeValues = header.Substring(6).Split('-'); 325 string[] rangeValues = header.Substring(6).Split('-');
326
306 if (rangeValues.Length == 2) 327 if (rangeValues.Length == 2)
307 { 328 {
308 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) 329 if (!Int32.TryParse(rangeValues[0], out start))
330 return false;
331
332 string rawEnd = rangeValues[1];
333
334 if (rawEnd == "")
335 {
336 end = -1;
337 return true;
338 }
339 else if (Int32.TryParse(rawEnd, out end))
340 {
309 return true; 341 return true;
342 }
310 } 343 }
311 } 344 }
312 345
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/Capabilities/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
index a681fb6..f8f63f4 100644
--- a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs
index 9a6ca86..11a2698 100644
--- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs
+++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs
@@ -435,4 +435,4 @@ namespace OpenSim.Capabilities.Handlers
435 return llsdItem; 435 return llsdItem;
436 } 436 }
437 } 437 }
438} \ No newline at end of file 438}
diff --git a/OpenSim/Capabilities/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Properties/AssemblyInfo.cs
index 26254f2..f8a9dae 100644
--- a/OpenSim/Capabilities/Properties/AssemblyInfo.cs
+++ b/OpenSim/Capabilities/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs b/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs
index c240f90..9c0c784 100644
--- a/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs
+++ b/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/ConsoleClient/Requester.cs b/OpenSim/ConsoleClient/Requester.cs
index aabb02c..0a21328 100644
--- a/OpenSim/ConsoleClient/Requester.cs
+++ b/OpenSim/ConsoleClient/Requester.cs
@@ -44,7 +44,6 @@ namespace OpenSim.ConsoleClient
44 ReplyDelegate action) 44 ReplyDelegate action)
45 { 45 {
46 WebRequest request = WebRequest.Create(requestUrl); 46 WebRequest request = WebRequest.Create(requestUrl);
47 WebResponse response = null;
48 47
49 request.Method = "POST"; 48 request.Method = "POST";
50 49
@@ -64,16 +63,18 @@ namespace OpenSim.ConsoleClient
64 { 63 {
65 string reply = String.Empty; 64 string reply = String.Empty;
66 65
67 response = request.EndGetResponse(ar); 66 using (WebResponse response = request.EndGetResponse(ar))
68
69 try
70 { 67 {
71 StreamReader r = new StreamReader(response.GetResponseStream()); 68 try
72 reply = r.ReadToEnd(); 69 {
70 using (Stream s = response.GetResponseStream())
71 using (StreamReader r = new StreamReader(s))
72 reply = r.ReadToEnd();
73 73
74 } 74 }
75 catch (System.InvalidOperationException) 75 catch (System.InvalidOperationException)
76 { 76 {
77 }
77 } 78 }
78 79
79 action(requestUrl, data, reply); 80 action(requestUrl, data, reply);
diff --git a/OpenSim/Data/IGroupsData.cs b/OpenSim/Data/IGroupsData.cs
new file mode 100644
index 0000000..c11e649
--- /dev/null
+++ b/OpenSim/Data/IGroupsData.cs
@@ -0,0 +1,144 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using OpenSim.Data;
30using OpenMetaverse;
31
32namespace OpenSim.Data
33{
34 public class GroupData
35 {
36 public UUID GroupID;
37 public Dictionary<string, string> Data;
38 }
39
40 public class MembershipData
41 {
42 public UUID GroupID;
43 public string PrincipalID;
44 public Dictionary<string, string> Data;
45 }
46
47 public class RoleData
48 {
49 public UUID GroupID;
50 public UUID RoleID;
51 public Dictionary<string, string> Data;
52 }
53
54 public class RoleMembershipData
55 {
56 public UUID GroupID;
57 public UUID RoleID;
58 public string PrincipalID;
59 }
60
61 public class PrincipalData
62 {
63 public string PrincipalID;
64 public UUID ActiveGroupID;
65 }
66
67 public class InvitationData
68 {
69 public UUID InviteID;
70 public UUID GroupID;
71 public UUID RoleID;
72 public string PrincipalID;
73 public Dictionary<string, string> Data;
74 }
75
76 public class NoticeData
77 {
78 public UUID GroupID;
79 public UUID NoticeID;
80 public Dictionary<string, string> Data;
81 }
82
83
84 public interface IGroupsData
85 {
86 // groups table
87 bool StoreGroup(GroupData data);
88 GroupData RetrieveGroup(UUID groupID);
89 GroupData RetrieveGroup(string name);
90 GroupData[] RetrieveGroups(string pattern);
91 bool DeleteGroup(UUID groupID);
92 int GroupsCount();
93
94 // membership table
95 MembershipData RetrieveMember(UUID groupID, string pricipalID);
96 MembershipData[] RetrieveMembers(UUID groupID);
97 MembershipData[] RetrieveMemberships(string pricipalID);
98 bool StoreMember(MembershipData data);
99 bool DeleteMember(UUID groupID, string pricipalID);
100 int MemberCount(UUID groupID);
101
102 // roles table
103 bool StoreRole(RoleData data);
104 RoleData RetrieveRole(UUID groupID, UUID roleID);
105 RoleData[] RetrieveRoles(UUID groupID);
106 bool DeleteRole(UUID groupID, UUID roleID);
107 int RoleCount(UUID groupID);
108
109 // rolememberhip table
110 RoleMembershipData[] RetrieveRolesMembers(UUID groupID);
111 RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID);
112 RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID);
113 RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID);
114 int RoleMemberCount(UUID groupID, UUID roleID);
115 bool StoreRoleMember(RoleMembershipData data);
116 bool DeleteRoleMember(RoleMembershipData data);
117 bool DeleteMemberAllRoles(UUID groupID, string principalID);
118
119 // principals table
120 bool StorePrincipal(PrincipalData data);
121 PrincipalData RetrievePrincipal(string principalID);
122 bool DeletePrincipal(string principalID);
123
124 // invites table
125 bool StoreInvitation(InvitationData data);
126 InvitationData RetrieveInvitation(UUID inviteID);
127 InvitationData RetrieveInvitation(UUID groupID, string principalID);
128 bool DeleteInvite(UUID inviteID);
129 void DeleteOldInvites();
130
131 // notices table
132 bool StoreNotice(NoticeData data);
133 NoticeData RetrieveNotice(UUID noticeID);
134 NoticeData[] RetrieveNotices(UUID groupID);
135 bool DeleteNotice(UUID noticeID);
136 void DeleteOldNotices();
137
138 // combinations
139 MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID);
140 MembershipData[] RetrievePrincipalGroupMemberships(string principalID);
141
142 // Misc
143 }
144}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs b/OpenSim/Data/IOfflineIMData.cs
index f3be028..e780304 100644
--- a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs
+++ b/OpenSim/Data/IOfflineIMData.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -25,22 +25,25 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Collections.Generic;
29using OpenSim.Data;
28using OpenMetaverse; 30using OpenMetaverse;
29 31
30namespace OpenSim.Region.Framework.Scenes.Scripting 32namespace OpenSim.Data
31{ 33{
32 public interface IScriptHost 34 public class OfflineIMData
33 { 35 {
34 string Name { get; set; } 36 public UUID PrincipalID;
35 string Description { get; set; } 37 public Dictionary<string, string> Data;
38 }
36 39
37 UUID UUID { get; }
38 UUID OwnerID { get; }
39 UUID CreatorID { get; }
40 Vector3 AbsolutePosition { get; }
41 40
42 string SitName { get; set; } 41 public interface IOfflineIMData
43 string TouchName { get; set; } 42 {
44 void SetText(string text, Vector3 color, double alpha); 43 OfflineIMData[] Get(string field, string val);
44 long GetCount(string field, string key);
45 bool Store(OfflineIMData data);
46 bool Delete(string field, string val);
47 void DeleteOld();
45 } 48 }
46} 49}
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/ApplicationPlugins/Rest/Inventory/IRestHandler.cs b/OpenSim/Data/IXGroupData.cs
index a88fe88..2965e8c 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs
+++ b/OpenSim/Data/IXGroupData.cs
@@ -25,35 +25,47 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework.Servers.HttpServer; 28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
29 32
30namespace OpenSim.ApplicationPlugins.Rest.Inventory 33namespace OpenSim.Data
31{ 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;
32 50
33 /// <remarks> 51 public XGroup Clone()
34 /// The handler delegates are not noteworthy. The allocator allows 52 {
35 /// a given handler to optionally subclass the base RequestData 53 return (XGroup)MemberwiseClone();
36 /// structure to carry any locally required per-request state 54 }
37 /// needed. 55 }
38 /// </remarks>
39
40 public delegate void RestMethodHandler(RequestData rdata);
41 public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path);
42 56
43 /// <summary> 57 /// <summary>
44 /// This interface exports the generic plugin-handling services 58 /// Early stub interface for groups data, not final.
45 /// available to each loaded REST services module (IRest implementation)
46 /// </summary> 59 /// </summary>
47 60 /// <remarks>
48 internal interface IRestHandler 61 /// Currently in-use only for regression test purposes. Needs to be filled out over time.
62 /// </remarks>
63 public interface IXGroupData
49 { 64 {
50 65 bool StoreGroup(XGroup group);
51 string MsgId { get; } 66 XGroup[] GetGroups(string field, string val);
52 string RequestId { get; } 67 XGroup[] GetGroups(string[] fields, string[] vals);
53 68 bool DeleteGroups(string field, string val);
54 void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma); 69 bool DeleteGroups(string[] fields, string[] vals);
55 void AddStreamHandler(string httpMethod, string path, RestMethod method);
56
57 } 70 }
58 71} \ No newline at end of file
59}
diff --git a/OpenSim/Data/MSSQL/MSSQLAssetData.cs b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
index c882555..12f2477 100644
--- a/OpenSim/Data/MSSQL/MSSQLAssetData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
@@ -163,14 +163,18 @@ namespace OpenSim.Data.MSSQL
163 if (asset.Name.Length > 64) 163 if (asset.Name.Length > 64)
164 { 164 {
165 assetName = asset.Name.Substring(0, 64); 165 assetName = asset.Name.Substring(0, 64);
166 m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); 166 m_log.WarnFormat(
167 "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
168 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
167 } 169 }
168 170
169 string assetDescription = asset.Description; 171 string assetDescription = asset.Description;
170 if (asset.Description.Length > 64) 172 if (asset.Description.Length > 64)
171 { 173 {
172 assetDescription = asset.Description.Substring(0, 64); 174 assetDescription = asset.Description.Substring(0, 64);
173 m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); 175 m_log.WarnFormat(
176 "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
177 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
174 } 178 }
175 179
176 using (SqlConnection conn = new SqlConnection(m_connectionString)) 180 using (SqlConnection conn = new SqlConnection(m_connectionString))
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/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index 5bb6ec9..00af3a0 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -351,7 +351,8 @@ IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID)
351 ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice, 351 ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice,
352 SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem, 352 SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem,
353 ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches, 353 ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches,
354 LinkNumber = @LinkNumber, MediaURL = @MediaURL 354 LinkNumber = @LinkNumber, MediaURL = @MediaURL, DynAttrs = @DynAttrs,
355 PhysicsShapeType = @PhysicsShapeType, Density = @Density, GravityModifier = @GravityModifier, Friction = @Friction, Restitution = @Restitution
355 WHERE UUID = @UUID 356 WHERE UUID = @UUID
356 END 357 END
357ELSE 358ELSE
@@ -366,7 +367,8 @@ ELSE
366 PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX, 367 PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX,
367 OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ, 368 OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ,
368 ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA, 369 ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA,
369 ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL 370 ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, DynAttrs,
371 PhysicsShapeType, Density, GravityModifier, Friction, Restitution
370 ) VALUES ( 372 ) VALUES (
371 @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask, 373 @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask,
372 @EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX, 374 @EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX,
@@ -376,7 +378,8 @@ ELSE
376 @PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX, 378 @PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX,
377 @OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ, 379 @OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ,
378 @ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA, 380 @ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA,
379 @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL 381 @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @DynAttrs,
382 @PhysicsShapeType, @Density, @GravityModifier, @Friction, @Restitution
380 ) 383 )
381 END"; 384 END";
382 385
@@ -1691,6 +1694,17 @@ VALUES
1691 1694
1692 if (!(primRow["MediaURL"] is System.DBNull)) 1695 if (!(primRow["MediaURL"] is System.DBNull))
1693 prim.MediaUrl = (string)primRow["MediaURL"]; 1696 prim.MediaUrl = (string)primRow["MediaURL"];
1697
1698 if (!(primRow["DynAttrs"] is System.DBNull))
1699 prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]);
1700 else
1701 prim.DynAttrs = new DAMap();
1702
1703 prim.PhysicsShapeType = Convert.ToByte(primRow["PhysicsShapeType"]);
1704 prim.Density = Convert.ToSingle(primRow["Density"]);
1705 prim.GravityModifier = Convert.ToSingle(primRow["GravityModifier"]);
1706 prim.Friction = Convert.ToSingle(primRow["Friction"]);
1707 prim.Restitution = Convert.ToSingle(primRow["Restitution"]);
1694 1708
1695 return prim; 1709 return prim;
1696 } 1710 }
@@ -1749,7 +1763,6 @@ VALUES
1749 baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]); 1763 baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]);
1750 } 1764 }
1751 1765
1752
1753 return baseShape; 1766 return baseShape;
1754 } 1767 }
1755 1768
@@ -2086,6 +2099,17 @@ VALUES
2086 parameters.Add(_Database.CreateParameter("PassTouches", 0)); 2099 parameters.Add(_Database.CreateParameter("PassTouches", 0));
2087 parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); 2100 parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum));
2088 parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); 2101 parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl));
2102
2103 if (prim.DynAttrs.Count > 0)
2104 parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml()));
2105 else
2106 parameters.Add(_Database.CreateParameter("DynAttrs", null));
2107
2108 parameters.Add(_Database.CreateParameter("PhysicsShapeType", prim.PhysicsShapeType));
2109 parameters.Add(_Database.CreateParameter("Density", (double)prim.Density));
2110 parameters.Add(_Database.CreateParameter("GravityModifier", (double)prim.GravityModifier));
2111 parameters.Add(_Database.CreateParameter("Friction", (double)prim.Friction));
2112 parameters.Add(_Database.CreateParameter("Restitution", (double)prim.Restitution));
2089 2113
2090 return parameters.ToArray(); 2114 return parameters.ToArray();
2091 } 2115 }
@@ -2143,7 +2167,6 @@ VALUES
2143 parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml())); 2167 parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml()));
2144 } 2168 }
2145 2169
2146
2147 return parameters.ToArray(); 2170 return parameters.ToArray();
2148 } 2171 }
2149 2172
diff --git a/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs
index 1a67e70..9bc580e 100644
--- a/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs
+++ b/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
index 350e548..b84c2a4 100644
--- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
@@ -1148,3 +1148,23 @@ CREATE TABLE [dbo].[regionenvironment](
1148) ON [PRIMARY] 1148) ON [PRIMARY]
1149 1149
1150COMMIT 1150COMMIT
1151
1152:VERSION 38 #---------------- Dynamic attributes
1153
1154BEGIN TRANSACTION
1155
1156ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
1157
1158COMMIT
1159
1160:VERSION 39 #---------------- Extra physics params
1161
1162BEGIN TRANSACTION
1163
1164ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
1165ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
1166ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
1167ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
1168ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
1169
1170COMMIT
diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs
index 20df234..21dd5aa 100644
--- a/OpenSim/Data/MySQL/MySQLAssetData.cs
+++ b/OpenSim/Data/MySQL/MySQLAssetData.cs
@@ -173,14 +173,18 @@ namespace OpenSim.Data.MySQL
173 if (asset.Name.Length > 64) 173 if (asset.Name.Length > 64)
174 { 174 {
175 assetName = asset.Name.Substring(0, 64); 175 assetName = asset.Name.Substring(0, 64);
176 m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); 176 m_log.WarnFormat(
177 "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
178 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
177 } 179 }
178 180
179 string assetDescription = asset.Description; 181 string assetDescription = asset.Description;
180 if (asset.Description.Length > 64) 182 if (asset.Description.Length > 64)
181 { 183 {
182 assetDescription = asset.Description.Substring(0, 64); 184 assetDescription = asset.Description.Substring(0, 64);
183 m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); 185 m_log.WarnFormat(
186 "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
187 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
184 } 188 }
185 189
186 try 190 try
diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
index f6731c0..dc657c8 100644
--- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
+++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
@@ -306,5 +306,65 @@ namespace OpenSim.Data.MySQL
306 return ExecuteNonQuery(cmd) > 0; 306 return ExecuteNonQuery(cmd) > 0;
307 } 307 }
308 } 308 }
309
310 public long GetCount(string field, string key)
311 {
312 return GetCount(new string[] { field }, new string[] { key });
313 }
314
315 public long GetCount(string[] fields, string[] keys)
316 {
317 if (fields.Length != keys.Length)
318 return 0;
319
320 List<string> terms = new List<string>();
321
322 using (MySqlCommand cmd = new MySqlCommand())
323 {
324 for (int i = 0; i < fields.Length; i++)
325 {
326 cmd.Parameters.AddWithValue(fields[i], keys[i]);
327 terms.Add("`" + fields[i] + "` = ?" + fields[i]);
328 }
329
330 string where = String.Join(" and ", terms.ToArray());
331
332 string query = String.Format("select count(*) from {0} where {1}",
333 m_Realm, where);
334
335 cmd.CommandText = query;
336
337 Object result = DoQueryScalar(cmd);
338
339 return Convert.ToInt64(result);
340 }
341 }
342
343 public long GetCount(string where)
344 {
345 using (MySqlCommand cmd = new MySqlCommand())
346 {
347 string query = String.Format("select count(*) from {0} where {1}",
348 m_Realm, where);
349
350 cmd.CommandText = query;
351
352 object result = DoQueryScalar(cmd);
353
354 return Convert.ToInt64(result);
355 }
356 }
357
358 public object DoQueryScalar(MySqlCommand cmd)
359 {
360 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
361 {
362 dbcon.Open();
363 cmd.Connection = dbcon;
364
365 return cmd.ExecuteScalar();
366 }
367 }
368
309 } 369 }
310} 370}
diff --git a/OpenSim/Data/MySQL/MySQLGroupsData.cs b/OpenSim/Data/MySQL/MySQLGroupsData.cs
new file mode 100644
index 0000000..2a1bd6c
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLGroupsData.cs
@@ -0,0 +1,484 @@
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.Reflection;
32
33using OpenSim.Framework;
34using OpenSim.Data.MySQL;
35
36using OpenMetaverse;
37using MySql.Data.MySqlClient;
38
39namespace OpenSim.Data.MySQL
40{
41 public class MySQLGroupsData : IGroupsData
42 {
43 private MySqlGroupsGroupsHandler m_Groups;
44 private MySqlGroupsMembershipHandler m_Membership;
45 private MySqlGroupsRolesHandler m_Roles;
46 private MySqlGroupsRoleMembershipHandler m_RoleMembership;
47 private MySqlGroupsInvitesHandler m_Invites;
48 private MySqlGroupsNoticesHandler m_Notices;
49 private MySqlGroupsPrincipalsHandler m_Principals;
50
51 public MySQLGroupsData(string connectionString, string realm)
52 {
53 m_Groups = new MySqlGroupsGroupsHandler(connectionString, realm + "_groups", realm + "_Store");
54 m_Membership = new MySqlGroupsMembershipHandler(connectionString, realm + "_membership");
55 m_Roles = new MySqlGroupsRolesHandler(connectionString, realm + "_roles");
56 m_RoleMembership = new MySqlGroupsRoleMembershipHandler(connectionString, realm + "_rolemembership");
57 m_Invites = new MySqlGroupsInvitesHandler(connectionString, realm + "_invites");
58 m_Notices = new MySqlGroupsNoticesHandler(connectionString, realm + "_notices");
59 m_Principals = new MySqlGroupsPrincipalsHandler(connectionString, realm + "_principals");
60 }
61
62 #region groups table
63 public bool StoreGroup(GroupData data)
64 {
65 return m_Groups.Store(data);
66 }
67
68 public GroupData RetrieveGroup(UUID groupID)
69 {
70 GroupData[] groups = m_Groups.Get("GroupID", groupID.ToString());
71 if (groups.Length > 0)
72 return groups[0];
73
74 return null;
75 }
76
77 public GroupData RetrieveGroup(string name)
78 {
79 GroupData[] groups = m_Groups.Get("Name", name);
80 if (groups.Length > 0)
81 return groups[0];
82
83 return null;
84 }
85
86 public GroupData[] RetrieveGroups(string pattern)
87 {
88 if (string.IsNullOrEmpty(pattern))
89 pattern = "1 ORDER BY Name LIMIT 100";
90 else
91 pattern = string.Format("Name LIKE %{0}% ORDER BY Name LIMIT 100", pattern);
92
93 return m_Groups.Get(pattern);
94 }
95
96 public bool DeleteGroup(UUID groupID)
97 {
98 return m_Groups.Delete("GroupID", groupID.ToString());
99 }
100
101 public int GroupsCount()
102 {
103 return (int)m_Groups.GetCount("Location=\"\"");
104 }
105
106 #endregion
107
108 #region membership table
109 public MembershipData[] RetrieveMembers(UUID groupID)
110 {
111 return m_Membership.Get("GroupID", groupID.ToString());
112 }
113
114 public MembershipData RetrieveMember(UUID groupID, string pricipalID)
115 {
116 MembershipData[] m = m_Membership.Get(new string[] { "GroupID", "PrincipalID" },
117 new string[] { groupID.ToString(), pricipalID });
118 if (m != null && m.Length > 0)
119 return m[0];
120
121 return null;
122 }
123
124 public MembershipData[] RetrieveMemberships(string pricipalID)
125 {
126 return m_Membership.Get("PrincipalID", pricipalID.ToString());
127 }
128
129 public bool StoreMember(MembershipData data)
130 {
131 return m_Membership.Store(data);
132 }
133
134 public bool DeleteMember(UUID groupID, string pricipalID)
135 {
136 return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" },
137 new string[] { groupID.ToString(), pricipalID });
138 }
139
140 public int MemberCount(UUID groupID)
141 {
142 return (int)m_Membership.GetCount("GroupID", groupID.ToString());
143 }
144 #endregion
145
146 #region roles table
147 public bool StoreRole(RoleData data)
148 {
149 return m_Roles.Store(data);
150 }
151
152 public RoleData RetrieveRole(UUID groupID, UUID roleID)
153 {
154 RoleData[] data = m_Roles.Get(new string[] { "GroupID", "RoleID" },
155 new string[] { groupID.ToString(), roleID.ToString() });
156
157 if (data != null && data.Length > 0)
158 return data[0];
159
160 return null;
161 }
162
163 public RoleData[] RetrieveRoles(UUID groupID)
164 {
165 //return m_Roles.RetrieveRoles(groupID);
166 return m_Roles.Get("GroupID", groupID.ToString());
167 }
168
169 public bool DeleteRole(UUID groupID, UUID roleID)
170 {
171 return m_Roles.Delete(new string[] { "GroupID", "RoleID" },
172 new string[] { groupID.ToString(), roleID.ToString() });
173 }
174
175 public int RoleCount(UUID groupID)
176 {
177 return (int)m_Roles.GetCount("GroupID", groupID.ToString());
178 }
179
180
181 #endregion
182
183 #region rolememberhip table
184 public RoleMembershipData[] RetrieveRolesMembers(UUID groupID)
185 {
186 RoleMembershipData[] data = m_RoleMembership.Get("GroupID", groupID.ToString());
187
188 return data;
189 }
190
191 public RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID)
192 {
193 RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID" },
194 new string[] { groupID.ToString(), roleID.ToString() });
195
196 return data;
197 }
198
199 public RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID)
200 {
201 RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "PrincipalID" },
202 new string[] { groupID.ToString(), principalID.ToString() });
203
204 return data;
205 }
206
207 public RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID)
208 {
209 RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID", "PrincipalID" },
210 new string[] { groupID.ToString(), roleID.ToString(), principalID.ToString() });
211
212 if (data != null && data.Length > 0)
213 return data[0];
214
215 return null;
216 }
217
218 public int RoleMemberCount(UUID groupID, UUID roleID)
219 {
220 return (int)m_RoleMembership.GetCount(new string[] { "GroupID", "RoleID" },
221 new string[] { groupID.ToString(), roleID.ToString() });
222 }
223
224 public bool StoreRoleMember(RoleMembershipData data)
225 {
226 return m_RoleMembership.Store(data);
227 }
228
229 public bool DeleteRoleMember(RoleMembershipData data)
230 {
231 return m_RoleMembership.Delete(new string[] { "GroupID", "RoleID", "PrincipalID"},
232 new string[] { data.GroupID.ToString(), data.RoleID.ToString(), data.PrincipalID });
233 }
234
235 public bool DeleteMemberAllRoles(UUID groupID, string principalID)
236 {
237 return m_RoleMembership.Delete(new string[] { "GroupID", "PrincipalID" },
238 new string[] { groupID.ToString(), principalID });
239 }
240
241 #endregion
242
243 #region principals table
244 public bool StorePrincipal(PrincipalData data)
245 {
246 return m_Principals.Store(data);
247 }
248
249 public PrincipalData RetrievePrincipal(string principalID)
250 {
251 PrincipalData[] p = m_Principals.Get("PrincipalID", principalID);
252 if (p != null && p.Length > 0)
253 return p[0];
254
255 return null;
256 }
257
258 public bool DeletePrincipal(string principalID)
259 {
260 return m_Principals.Delete("PrincipalID", principalID);
261 }
262 #endregion
263
264 #region invites table
265
266 public bool StoreInvitation(InvitationData data)
267 {
268 return m_Invites.Store(data);
269 }
270
271 public InvitationData RetrieveInvitation(UUID inviteID)
272 {
273 InvitationData[] invites = m_Invites.Get("InviteID", inviteID.ToString());
274
275 if (invites != null && invites.Length > 0)
276 return invites[0];
277
278 return null;
279 }
280
281 public InvitationData RetrieveInvitation(UUID groupID, string principalID)
282 {
283 InvitationData[] invites = m_Invites.Get(new string[] { "GroupID", "PrincipalID" },
284 new string[] { groupID.ToString(), principalID });
285
286 if (invites != null && invites.Length > 0)
287 return invites[0];
288
289 return null;
290 }
291
292 public bool DeleteInvite(UUID inviteID)
293 {
294 return m_Invites.Delete("InviteID", inviteID.ToString());
295 }
296
297 public void DeleteOldInvites()
298 {
299 m_Invites.DeleteOld();
300 }
301
302 #endregion
303
304 #region notices table
305
306 public bool StoreNotice(NoticeData data)
307 {
308 return m_Notices.Store(data);
309 }
310
311 public NoticeData RetrieveNotice(UUID noticeID)
312 {
313 NoticeData[] notices = m_Notices.Get("NoticeID", noticeID.ToString());
314
315 if (notices != null && notices.Length > 0)
316 return notices[0];
317
318 return null;
319 }
320
321 public NoticeData[] RetrieveNotices(UUID groupID)
322 {
323 NoticeData[] notices = m_Notices.Get("GroupID", groupID.ToString());
324
325 return notices;
326 }
327
328 public bool DeleteNotice(UUID noticeID)
329 {
330 return m_Notices.Delete("NoticeID", noticeID.ToString());
331 }
332
333 public void DeleteOldNotices()
334 {
335 m_Notices.DeleteOld();
336 }
337
338 #endregion
339
340 #region combinations
341 public MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID)
342 {
343 // TODO
344 return null;
345 }
346 public MembershipData[] RetrievePrincipalGroupMemberships(string principalID)
347 {
348 // TODO
349 return null;
350 }
351
352 #endregion
353 }
354
355 public class MySqlGroupsGroupsHandler : MySQLGenericTableHandler<GroupData>
356 {
357 protected override Assembly Assembly
358 {
359 // WARNING! Moving migrations to this assembly!!!
360 get { return GetType().Assembly; }
361 }
362
363 public MySqlGroupsGroupsHandler(string connectionString, string realm, string store)
364 : base(connectionString, realm, store)
365 {
366 }
367
368 }
369
370 public class MySqlGroupsMembershipHandler : MySQLGenericTableHandler<MembershipData>
371 {
372 protected override Assembly Assembly
373 {
374 // WARNING! Moving migrations to this assembly!!!
375 get { return GetType().Assembly; }
376 }
377
378 public MySqlGroupsMembershipHandler(string connectionString, string realm)
379 : base(connectionString, realm, string.Empty)
380 {
381 }
382
383 }
384
385 public class MySqlGroupsRolesHandler : MySQLGenericTableHandler<RoleData>
386 {
387 protected override Assembly Assembly
388 {
389 // WARNING! Moving migrations to this assembly!!!
390 get { return GetType().Assembly; }
391 }
392
393 public MySqlGroupsRolesHandler(string connectionString, string realm)
394 : base(connectionString, realm, string.Empty)
395 {
396 }
397
398 }
399
400 public class MySqlGroupsRoleMembershipHandler : MySQLGenericTableHandler<RoleMembershipData>
401 {
402 protected override Assembly Assembly
403 {
404 // WARNING! Moving migrations to this assembly!!!
405 get { return GetType().Assembly; }
406 }
407
408 public MySqlGroupsRoleMembershipHandler(string connectionString, string realm)
409 : base(connectionString, realm, string.Empty)
410 {
411 }
412
413 }
414
415 public class MySqlGroupsInvitesHandler : MySQLGenericTableHandler<InvitationData>
416 {
417 protected override Assembly Assembly
418 {
419 // WARNING! Moving migrations to this assembly!!!
420 get { return GetType().Assembly; }
421 }
422
423 public MySqlGroupsInvitesHandler(string connectionString, string realm)
424 : base(connectionString, realm, string.Empty)
425 {
426 }
427
428 public void DeleteOld()
429 {
430 uint now = (uint)Util.UnixTimeSinceEpoch();
431
432 using (MySqlCommand cmd = new MySqlCommand())
433 {
434 cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm);
435 cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
436
437 ExecuteNonQuery(cmd);
438 }
439
440 }
441 }
442
443 public class MySqlGroupsNoticesHandler : MySQLGenericTableHandler<NoticeData>
444 {
445 protected override Assembly Assembly
446 {
447 // WARNING! Moving migrations to this assembly!!!
448 get { return GetType().Assembly; }
449 }
450
451 public MySqlGroupsNoticesHandler(string connectionString, string realm)
452 : base(connectionString, realm, string.Empty)
453 {
454 }
455
456 public void DeleteOld()
457 {
458 uint now = (uint)Util.UnixTimeSinceEpoch();
459
460 using (MySqlCommand cmd = new MySqlCommand())
461 {
462 cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm);
463 cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
464
465 ExecuteNonQuery(cmd);
466 }
467
468 }
469 }
470
471 public class MySqlGroupsPrincipalsHandler : MySQLGenericTableHandler<PrincipalData>
472 {
473 protected override Assembly Assembly
474 {
475 // WARNING! Moving migrations to this assembly!!!
476 get { return GetType().Assembly; }
477 }
478
479 public MySqlGroupsPrincipalsHandler(string connectionString, string realm)
480 : base(connectionString, realm, string.Empty)
481 {
482 }
483 }
484}
diff --git a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs
index 283fa2e..252f358 100644
--- a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs
+++ b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs
@@ -25,48 +25,38 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.IO; 28using System;
29using System.Text; 29using System.Collections;
30using System.Xml; 30using System.Collections.Generic;
31using System.Reflection;
31 32
32namespace OpenSim.ApplicationPlugins.Rest 33using OpenSim.Framework;
33{ 34using OpenSim.Data.MySQL;
34 public class RestXmlWriter: XmlTextWriter
35 {
36 private StringWriter m_sw = null;
37
38 public RestXmlWriter(StringWriter sw) : base(sw)
39 {
40 m_sw = sw;
41 Formatting = Formatting.Indented;
42 }
43 35
44 public RestXmlWriter(TextWriter textWriter) : base(textWriter) 36using OpenMetaverse;
45 { 37using MySql.Data.MySqlClient;
46 }
47 38
48 public RestXmlWriter(Stream stream) 39namespace OpenSim.Data.MySQL
49 : this(stream, Encoding.UTF8) 40{
41 public class MySQLOfflineIMData : MySQLGenericTableHandler<OfflineIMData>, IOfflineIMData
42 {
43 public MySQLOfflineIMData(string connectionString, string realm)
44 : base(connectionString, realm, "IM_Store")
50 { 45 {
51 } 46 }
52 47
53 public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc) 48 public void DeleteOld()
54 { 49 {
55 } 50 uint now = (uint)Util.UnixTimeSinceEpoch();
56 51
57 public override void WriteStartDocument() 52 using (MySqlCommand cmd = new MySqlCommand())
58 { 53 {
59 } 54 cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm);
55 cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
60 56
61 public override void WriteStartDocument(bool standalone) 57 ExecuteNonQuery(cmd);
62 { 58 }
63 }
64 59
65 public override string ToString()
66 {
67 Flush();
68 Close();
69 return m_sw.ToString();
70 } 60 }
71 } 61 }
72} 62}
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/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 01b9299..5320543 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -176,7 +176,7 @@ namespace OpenSim.Data.MySQL
176 "PassCollisions, " + 176 "PassCollisions, " +
177 "LinkNumber, MediaURL, KeyframeMotion, " + 177 "LinkNumber, MediaURL, KeyframeMotion, " +
178 "PhysicsShapeType, Density, GravityModifier, " + 178 "PhysicsShapeType, Density, GravityModifier, " +
179 "Friction, Restitution, Vehicle " + 179 "Friction, Restitution, Vehicle, DynAttrs " +
180 ") values (" + "?UUID, " + 180 ") values (" + "?UUID, " +
181 "?CreationDate, ?Name, ?Text, " + 181 "?CreationDate, ?Name, ?Text, " +
182 "?Description, ?SitName, ?TouchName, " + 182 "?Description, ?SitName, ?TouchName, " +
@@ -211,7 +211,7 @@ namespace OpenSim.Data.MySQL
211 "?CollisionSoundVolume, ?PassTouches, ?PassCollisions, " + 211 "?CollisionSoundVolume, ?PassTouches, ?PassCollisions, " +
212 "?LinkNumber, ?MediaURL, ?KeyframeMotion, " + 212 "?LinkNumber, ?MediaURL, ?KeyframeMotion, " +
213 "?PhysicsShapeType, ?Density, ?GravityModifier, " + 213 "?PhysicsShapeType, ?Density, ?GravityModifier, " +
214 "?Friction, ?Restitution, ?Vehicle)"; 214 "?Friction, ?Restitution, ?Vehicle, ?DynAttrs)";
215 215
216 FillPrimCommand(cmd, prim, obj.UUID, regionUUID); 216 FillPrimCommand(cmd, prim, obj.UUID, regionUUID);
217 217
@@ -228,7 +228,8 @@ namespace OpenSim.Data.MySQL
228 "PathTaperX, PathTaperY, PathTwist, " + 228 "PathTaperX, PathTaperY, PathTwist, " +
229 "PathTwistBegin, ProfileBegin, ProfileEnd, " + 229 "PathTwistBegin, ProfileBegin, ProfileEnd, " +
230 "ProfileCurve, ProfileHollow, Texture, " + 230 "ProfileCurve, ProfileHollow, Texture, " +
231 "ExtraParams, State, Media) values (?UUID, " + 231 "ExtraParams, State, Media) " +
232 "values (?UUID, " +
232 "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + 233 "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " +
233 "?PCode, ?PathBegin, ?PathEnd, " + 234 "?PCode, ?PathBegin, ?PathEnd, " +
234 "?PathScaleX, ?PathScaleY, " + 235 "?PathScaleX, ?PathScaleY, " +
@@ -1321,6 +1322,11 @@ namespace OpenSim.Data.MySQL
1321 1322
1322 if (!(row["MediaURL"] is System.DBNull)) 1323 if (!(row["MediaURL"] is System.DBNull))
1323 prim.MediaUrl = (string)row["MediaURL"]; 1324 prim.MediaUrl = (string)row["MediaURL"];
1325
1326 if (!(row["DynAttrs"] is System.DBNull))
1327 prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]);
1328 else
1329 prim.DynAttrs = new DAMap();
1324 1330
1325 if (!(row["KeyframeMotion"] is DBNull)) 1331 if (!(row["KeyframeMotion"] is DBNull))
1326 { 1332 {
@@ -1339,7 +1345,7 @@ namespace OpenSim.Data.MySQL
1339 prim.Density = (float)(double)row["Density"]; 1345 prim.Density = (float)(double)row["Density"];
1340 prim.GravityModifier = (float)(double)row["GravityModifier"]; 1346 prim.GravityModifier = (float)(double)row["GravityModifier"];
1341 prim.Friction = (float)(double)row["Friction"]; 1347 prim.Friction = (float)(double)row["Friction"];
1342 prim.Bounciness = (float)(double)row["Restitution"]; 1348 prim.Restitution = (float)(double)row["Restitution"];
1343 1349
1344 SOPVehicle vehicle = null; 1350 SOPVehicle vehicle = null;
1345 1351
@@ -1721,16 +1727,21 @@ namespace OpenSim.Data.MySQL
1721 else 1727 else
1722 cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); 1728 cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]);
1723 1729
1724 cmd.Parameters.AddWithValue("PhysicsShapeType", prim.PhysicsShapeType);
1725 cmd.Parameters.AddWithValue("Density", (double)prim.Density);
1726 cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier);
1727 cmd.Parameters.AddWithValue("Friction", (double)prim.Friction);
1728 cmd.Parameters.AddWithValue("Restitution", (double)prim.Bounciness);
1729
1730 if (prim.VehicleParams != null) 1730 if (prim.VehicleParams != null)
1731 cmd.Parameters.AddWithValue("Vehicle", prim.VehicleParams.ToXml2()); 1731 cmd.Parameters.AddWithValue("Vehicle", prim.VehicleParams.ToXml2());
1732 else 1732 else
1733 cmd.Parameters.AddWithValue("Vehicle", String.Empty); 1733 cmd.Parameters.AddWithValue("Vehicle", String.Empty);
1734
1735 if (prim.DynAttrs.Count > 0)
1736 cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml());
1737 else
1738 cmd.Parameters.AddWithValue("DynAttrs", null);
1739
1740 cmd.Parameters.AddWithValue("PhysicsShapeType", prim.PhysicsShapeType);
1741 cmd.Parameters.AddWithValue("Density", (double)prim.Density);
1742 cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier);
1743 cmd.Parameters.AddWithValue("Friction", (double)prim.Friction);
1744 cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution);
1734 } 1745 }
1735 1746
1736 /// <summary> 1747 /// <summary>
diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs
index 9a50373..15ac921 100644
--- a/OpenSim/Data/MySQL/MySQLXAssetData.cs
+++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs
@@ -50,6 +50,11 @@ namespace OpenSim.Data.MySQL
50 get { return GetType().Assembly; } 50 get { return GetType().Assembly; }
51 } 51 }
52 52
53 /// <summary>
54 /// Number of days that must pass before we update the access time on an asset when it has been fetched.
55 /// </summary>
56 private const int DaysBetweenAccessTimeUpdates = 30;
57
53 private bool m_enableCompression = false; 58 private bool m_enableCompression = false;
54 private string m_connectionString; 59 private string m_connectionString;
55 private object m_dbLock = new object(); 60 private object m_dbLock = new object();
@@ -133,10 +138,10 @@ namespace OpenSim.Data.MySQL
133 dbcon.Open(); 138 dbcon.Open();
134 139
135 using (MySqlCommand cmd = new MySqlCommand( 140 using (MySqlCommand cmd = new MySqlCommand(
136 "SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id", 141 "SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
137 dbcon)) 142 dbcon))
138 { 143 {
139 cmd.Parameters.AddWithValue("?id", assetID.ToString()); 144 cmd.Parameters.AddWithValue("?ID", assetID.ToString());
140 145
141 try 146 try
142 { 147 {
@@ -144,18 +149,18 @@ namespace OpenSim.Data.MySQL
144 { 149 {
145 if (dbReader.Read()) 150 if (dbReader.Read())
146 { 151 {
147 asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString()); 152 asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
148 asset.Data = (byte[])dbReader["data"]; 153 asset.Data = (byte[])dbReader["Data"];
149 asset.Description = (string)dbReader["description"]; 154 asset.Description = (string)dbReader["Description"];
150 155
151 string local = dbReader["local"].ToString(); 156 string local = dbReader["Local"].ToString();
152 if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) 157 if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
153 asset.Local = true; 158 asset.Local = true;
154 else 159 else
155 asset.Local = false; 160 asset.Local = false;
156 161
157 asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); 162 asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
158 asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); 163 asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
159 164
160 if (m_enableCompression) 165 if (m_enableCompression)
161 { 166 {
@@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL
171 // asset.ID, asset.Name, asset.Data.Length, compressedLength); 176 // asset.ID, asset.Name, asset.Data.Length, compressedLength);
172 } 177 }
173 } 178 }
179
180 UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
174 } 181 }
175 } 182 }
176 } 183 }
177 catch (Exception e) 184 catch (Exception e)
178 { 185 {
179 m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message); 186 m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
180 } 187 }
181 } 188 }
182 } 189 }
@@ -204,14 +211,18 @@ namespace OpenSim.Data.MySQL
204 if (asset.Name.Length > 64) 211 if (asset.Name.Length > 64)
205 { 212 {
206 assetName = asset.Name.Substring(0, 64); 213 assetName = asset.Name.Substring(0, 64);
207 m_log.Warn("[XASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); 214 m_log.WarnFormat(
215 "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
216 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
208 } 217 }
209 218
210 string assetDescription = asset.Description; 219 string assetDescription = asset.Description;
211 if (asset.Description.Length > 64) 220 if (asset.Description.Length > 64)
212 { 221 {
213 assetDescription = asset.Description.Substring(0, 64); 222 assetDescription = asset.Description.Substring(0, 64);
214 m_log.Warn("[XASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); 223 m_log.WarnFormat(
224 "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
225 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
215 } 226 }
216 227
217 if (m_enableCompression) 228 if (m_enableCompression)
@@ -238,23 +249,23 @@ namespace OpenSim.Data.MySQL
238 { 249 {
239 using (MySqlCommand cmd = 250 using (MySqlCommand cmd =
240 new MySqlCommand( 251 new MySqlCommand(
241 "replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" + 252 "replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" +
242 "VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)", 253 "VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
243 dbcon)) 254 dbcon))
244 { 255 {
245 // create unix epoch time 256 // create unix epoch time
246 int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); 257 int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
247 cmd.Parameters.AddWithValue("?id", asset.ID); 258 cmd.Parameters.AddWithValue("?ID", asset.ID);
248 cmd.Parameters.AddWithValue("?hash", hash); 259 cmd.Parameters.AddWithValue("?Hash", hash);
249 cmd.Parameters.AddWithValue("?name", assetName); 260 cmd.Parameters.AddWithValue("?Name", assetName);
250 cmd.Parameters.AddWithValue("?description", assetDescription); 261 cmd.Parameters.AddWithValue("?Description", assetDescription);
251 cmd.Parameters.AddWithValue("?asset_type", asset.Type); 262 cmd.Parameters.AddWithValue("?AssetType", asset.Type);
252 cmd.Parameters.AddWithValue("?local", asset.Local); 263 cmd.Parameters.AddWithValue("?Local", asset.Local);
253 cmd.Parameters.AddWithValue("?temporary", asset.Temporary); 264 cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
254 cmd.Parameters.AddWithValue("?create_time", now); 265 cmd.Parameters.AddWithValue("?CreateTime", now);
255 cmd.Parameters.AddWithValue("?access_time", now); 266 cmd.Parameters.AddWithValue("?AccessTime", now);
256 cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID); 267 cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
257 cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); 268 cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
258 cmd.ExecuteNonQuery(); 269 cmd.ExecuteNonQuery();
259 } 270 }
260 } 271 }
@@ -274,11 +285,11 @@ namespace OpenSim.Data.MySQL
274 { 285 {
275 using (MySqlCommand cmd = 286 using (MySqlCommand cmd =
276 new MySqlCommand( 287 new MySqlCommand(
277 "INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)", 288 "INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
278 dbcon)) 289 dbcon))
279 { 290 {
280 cmd.Parameters.AddWithValue("?hash", hash); 291 cmd.Parameters.AddWithValue("?Hash", hash);
281 cmd.Parameters.AddWithValue("?data", asset.Data); 292 cmd.Parameters.AddWithValue("?Data", asset.Data);
282 cmd.ExecuteNonQuery(); 293 cmd.ExecuteNonQuery();
283 } 294 }
284 } 295 }
@@ -299,41 +310,49 @@ namespace OpenSim.Data.MySQL
299 } 310 }
300 } 311 }
301 312
302// private void UpdateAccessTime(AssetBase asset) 313 /// <summary>
303// { 314 /// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
304// lock (m_dbLock) 315 /// </summary>
305// { 316 /// <remarks>
306// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 317 /// This gives us some insight into assets which haven't ben accessed for a long period. This is only done
307// { 318 /// over the threshold time to avoid excessive database writes as assets are fetched.
308// dbcon.Open(); 319 /// </remarks>
309// MySqlCommand cmd = 320 /// <param name='asset'></param>
310// new MySqlCommand("update assets set access_time=?access_time where id=?id", 321 /// <param name='accessTime'></param>
311// dbcon); 322 private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
312// 323 {
313// // need to ensure we dispose 324 DateTime now = DateTime.UtcNow;
314// try 325
315// { 326 if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
316// using (cmd) 327 return;
317// { 328
318// // create unix epoch time 329 lock (m_dbLock)
319// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); 330 {
320// cmd.Parameters.AddWithValue("?id", asset.ID); 331 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
321// cmd.Parameters.AddWithValue("?access_time", now); 332 {
322// cmd.ExecuteNonQuery(); 333 dbcon.Open();
323// cmd.Dispose(); 334 MySqlCommand cmd =
324// } 335 new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
325// } 336
326// catch (Exception e) 337 try
327// { 338 {
328// m_log.ErrorFormat( 339 using (cmd)
329// "[ASSETS DB]: " + 340 {
330// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() 341 // create unix epoch time
331// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); 342 cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
332// } 343 cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
333// } 344 cmd.ExecuteNonQuery();
334// } 345 }
335// 346 }
336// } 347 catch (Exception e)
348 {
349 m_log.ErrorFormat(
350 "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}",
351 assetMetadata.ID, assetMetadata.Name);
352 }
353 }
354 }
355 }
337 356
338 /// <summary> 357 /// <summary>
339 /// We assume we already have the m_dbLock. 358 /// We assume we already have the m_dbLock.
@@ -349,9 +368,9 @@ namespace OpenSim.Data.MySQL
349 368
350 bool exists = false; 369 bool exists = false;
351 370
352 using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon)) 371 using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon))
353 { 372 {
354 cmd.Parameters.AddWithValue("?hash", hash); 373 cmd.Parameters.AddWithValue("?Hash", hash);
355 374
356 try 375 try
357 { 376 {
@@ -391,9 +410,9 @@ namespace OpenSim.Data.MySQL
391 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 410 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
392 { 411 {
393 dbcon.Open(); 412 dbcon.Open();
394 using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon)) 413 using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon))
395 { 414 {
396 cmd.Parameters.AddWithValue("?id", uuid.ToString()); 415 cmd.Parameters.AddWithValue("?ID", uuid.ToString());
397 416
398 try 417 try
399 { 418 {
@@ -408,8 +427,7 @@ namespace OpenSim.Data.MySQL
408 } 427 }
409 catch (Exception e) 428 catch (Exception e)
410 { 429 {
411 m_log.ErrorFormat( 430 m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
412 "[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
413 } 431 }
414 } 432 }
415 } 433 }
@@ -418,6 +436,7 @@ namespace OpenSim.Data.MySQL
418 return assetExists; 436 return assetExists;
419 } 437 }
420 438
439
421 /// <summary> 440 /// <summary>
422 /// Returns a list of AssetMetadata objects. The list is a subset of 441 /// Returns a list of AssetMetadata objects. The list is a subset of
423 /// the entire data set offset by <paramref name="start" /> containing 442 /// the entire data set offset by <paramref name="start" /> containing
@@ -435,7 +454,7 @@ namespace OpenSim.Data.MySQL
435 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 454 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
436 { 455 {
437 dbcon.Open(); 456 dbcon.Open();
438 MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon); 457 MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon);
439 cmd.Parameters.AddWithValue("?start", start); 458 cmd.Parameters.AddWithValue("?start", start);
440 cmd.Parameters.AddWithValue("?count", count); 459 cmd.Parameters.AddWithValue("?count", count);
441 460
@@ -446,17 +465,19 @@ namespace OpenSim.Data.MySQL
446 while (dbReader.Read()) 465 while (dbReader.Read())
447 { 466 {
448 AssetMetadata metadata = new AssetMetadata(); 467 AssetMetadata metadata = new AssetMetadata();
449 metadata.Name = (string)dbReader["name"]; 468 metadata.Name = (string)dbReader["Name"];
450 metadata.Description = (string)dbReader["description"]; 469 metadata.Description = (string)dbReader["Description"];
451 metadata.Type = (sbyte)dbReader["asset_type"]; 470 metadata.Type = (sbyte)dbReader["AssetType"];
452 metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. 471 metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
453 metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); 472 metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
454 metadata.FullID = DBGuid.FromDB(dbReader["id"]); 473 metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
455 metadata.CreatorID = dbReader["creator_id"].ToString(); 474 metadata.CreatorID = dbReader["CreatorID"].ToString();
456 475
457 // We'll ignore this for now - it appears unused! 476 // We'll ignore this for now - it appears unused!
458// metadata.SHA1 = dbReader["hash"]); 477// metadata.SHA1 = dbReader["hash"]);
459 478
479 UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
480
460 retList.Add(metadata); 481 retList.Add(metadata);
461 } 482 }
462 } 483 }
@@ -481,9 +502,9 @@ namespace OpenSim.Data.MySQL
481 { 502 {
482 dbcon.Open(); 503 dbcon.Open();
483 504
484 using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon)) 505 using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
485 { 506 {
486 cmd.Parameters.AddWithValue("?id", id); 507 cmd.Parameters.AddWithValue("?ID", id);
487 cmd.ExecuteNonQuery(); 508 cmd.ExecuteNonQuery();
488 } 509 }
489 510
diff --git a/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs
index ab3fe36..1146d92 100644
--- a/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs
+++ b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Data/MySQL/Resources/IM_Store.migrations b/OpenSim/Data/MySQL/Resources/IM_Store.migrations
new file mode 100644
index 0000000..7cfcd43
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/IM_Store.migrations
@@ -0,0 +1,24 @@
1:VERSION 1 # --------------------------
2
3BEGIN;
4
5CREATE TABLE `im_offline` (
6 `ID` MEDIUMINT NOT NULL AUTO_INCREMENT,
7 `PrincipalID` char(36) NOT NULL default '',
8 `Message` text NOT NULL,
9 `TMStamp` timestamp NOT NULL,
10 PRIMARY KEY (`ID`),
11 KEY `PrincipalID` (`PrincipalID`)
12) ENGINE=MyISAM;
13
14COMMIT;
15
16:VERSION 2 # --------------------------
17
18BEGIN;
19
20INSERT INTO `im_offline` SELECT * from `diva_im_offline`;
21DROP TABLE `diva_im_offline`;
22DELETE FROM `migrations` WHERE name='diva_im_Store';
23
24COMMIT; \ No newline at end of file
diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
index c4b0832..bda1b6a 100644
--- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
@@ -902,3 +902,23 @@ BEGIN;
902CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`)); 902CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`));
903 903
904COMMIT; 904COMMIT;
905
906:VERSION 46 #---------------- Dynamic attributes
907
908BEGIN;
909
910ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
911
912COMMIT;
913
914:VERSION 47 #---------------- Extra physics params
915
916BEGIN;
917
918ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
919ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
920ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
921ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
922ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
923
924COMMIT;
diff --git a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations
index d3cca5e..0c49d0d 100644
--- a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations
@@ -3,24 +3,24 @@
3 3
4BEGIN; 4BEGIN;
5 5
6CREATE TABLE `xassetsmeta` ( 6CREATE TABLE `XAssetsMeta` (
7 `id` char(36) NOT NULL, 7 `ID` char(36) NOT NULL,
8 `hash` binary(32) NOT NULL, 8 `Hash` binary(32) NOT NULL,
9 `name` varchar(64) NOT NULL, 9 `Name` varchar(64) NOT NULL,
10 `description` varchar(64) NOT NULL, 10 `Description` varchar(64) NOT NULL,
11 `asset_type` tinyint(4) NOT NULL, 11 `AssetType` tinyint(4) NOT NULL,
12 `local` tinyint(1) NOT NULL, 12 `Local` tinyint(1) NOT NULL,
13 `temporary` tinyint(1) NOT NULL, 13 `Temporary` tinyint(1) NOT NULL,
14 `create_time` int(11) NOT NULL, 14 `CreateTime` int(11) NOT NULL,
15 `access_time` int(11) NOT NULL, 15 `AccessTime` int(11) NOT NULL,
16 `asset_flags` int(11) NOT NULL, 16 `AssetFlags` int(11) NOT NULL,
17 `creator_id` varchar(128) NOT NULL, 17 `CreatorID` varchar(128) NOT NULL,
18 PRIMARY KEY (`id`) 18 PRIMARY KEY (`id`)
19) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; 19) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
20 20
21CREATE TABLE `xassetsdata` ( 21CREATE TABLE `XAssetsData` (
22 `hash` binary(32) NOT NULL, 22 `Hash` binary(32) NOT NULL,
23 `data` longblob NOT NULL, 23 `Data` longblob NOT NULL,
24 PRIMARY KEY (`hash`) 24 PRIMARY KEY (`hash`)
25) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; 25) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
26 26
diff --git a/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations b/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations
new file mode 100644
index 0000000..9e6f1c1
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations
@@ -0,0 +1,115 @@
1:VERSION 1 # --------------------------
2
3BEGIN;
4
5CREATE TABLE `os_groups_groups` (
6 `GroupID` char(36) NOT NULL default '',
7 `Location` varchar(255) NOT NULL default '',
8 `Name` varchar(255) NOT NULL default '',
9 `Charter` text NOT NULL,
10 `InsigniaID` char(36) NOT NULL default '',
11 `FounderID` char(36) NOT NULL default '',
12 `MembershipFee` int(11) NOT NULL default '0',
13 `OpenEnrollment` varchar(255) NOT NULL default '',
14 `ShowInList` int(4) NOT NULL default '0',
15 `AllowPublish` int(4) NOT NULL default '0',
16 `MaturePublish` int(4) NOT NULL default '0',
17 `OwnerRoleID` char(36) NOT NULL default '',
18 PRIMARY KEY (`GroupID`),
19 UNIQUE KEY `Name` (`Name`),
20 FULLTEXT KEY `Name_2` (`Name`)
21) ENGINE=MyISAM;
22
23
24CREATE TABLE `os_groups_membership` (
25 `GroupID`char(36) NOT NULL default '',
26 `PrincipalID` VARCHAR(255) NOT NULL default '',
27 `SelectedRoleID` char(36) NOT NULL default '',
28 `Contribution` int(11) NOT NULL default '0',
29 `ListInProfile` int(4) NOT NULL default '1',
30 `AcceptNotices` int(4) NOT NULL default '1',
31 `AccessToken` char(36) NOT NULL default '',
32 PRIMARY KEY (`GroupID`,`PrincipalID`),
33 KEY `PrincipalID` (`PrincipalID`)
34) ENGINE=MyISAM;
35
36
37CREATE TABLE `os_groups_roles` (
38 `GroupID` char(36) NOT NULL default '',
39 `RoleID` char(36) NOT NULL default '',
40 `Name` varchar(255) NOT NULL default '',
41 `Description` varchar(255) NOT NULL default '',
42 `Title` varchar(255) NOT NULL default '',
43 `Powers` bigint(20) unsigned NOT NULL default '0',
44 PRIMARY KEY (`GroupID`,`RoleID`),
45 KEY `GroupID` (`GroupID`)
46) ENGINE=MyISAM;
47
48
49CREATE TABLE `os_groups_rolemembership` (
50 `GroupID` char(36) NOT NULL default '',
51 `RoleID` char(36) NOT NULL default '',
52 `PrincipalID` VARCHAR(255) NOT NULL default '',
53 PRIMARY KEY (`GroupID`,`RoleID`,`PrincipalID`),
54 KEY `PrincipalID` (`PrincipalID`)
55) ENGINE=MyISAM;
56
57
58CREATE TABLE `os_groups_invites` (
59 `InviteID` char(36) NOT NULL default '',
60 `GroupID` char(36) NOT NULL default '',
61 `RoleID` char(36) NOT NULL default '',
62 `PrincipalID` VARCHAR(255) NOT NULL default '',
63 `TMStamp` timestamp NOT NULL,
64 PRIMARY KEY (`InviteID`),
65 UNIQUE KEY `PrincipalGroup` (`GroupID`,`PrincipalID`)
66) ENGINE=MyISAM;
67
68
69CREATE TABLE `os_groups_notices` (
70 `GroupID` char(36) NOT NULL default '',
71 `NoticeID` char(36) NOT NULL default '',
72 `TMStamp` int(10) unsigned NOT NULL default '0',
73 `FromName` varchar(255) NOT NULL default '',
74 `Subject` varchar(255) NOT NULL default '',
75 `Message` text NOT NULL,
76 `HasAttachment` int(4) NOT NULL default '0',
77 `AttachmentType` int(4) NOT NULL default '0',
78 `AttachmentName` varchar(128) NOT NULL default '',
79 `AttachmentItemID` char(36) NOT NULL default '',
80 `AttachmentOwnerID` varchar(255) NOT NULL default '',
81 PRIMARY KEY (`NoticeID`),
82 KEY `GroupID` (`GroupID`),
83 KEY `TMStamp` (`TMStamp`)
84) ENGINE=MyISAM;
85
86CREATE TABLE `os_groups_principals` (
87 `PrincipalID` VARCHAR(255) NOT NULL default '',
88 `ActiveGroupID` char(36) NOT NULL default '',
89 PRIMARY KEY (`PrincipalID`)
90) ENGINE=MyISAM;
91
92COMMIT;
93
94:VERSION 2 # --------------------------
95
96BEGIN;
97
98INSERT INTO `os_groups_groups` SELECT * from `diva_groups_groups`;
99DROP TABLE `diva_groups_groups`;
100INSERT INTO `os_groups_membership` SELECT * from `diva_groups_membership`;
101DROP TABLE `diva_groups_membership`;
102INSERT INTO `os_groups_roles` SELECT * from `diva_groups_roles`;
103DROP TABLE `diva_groups_roles`;
104INSERT INTO `os_groups_rolemembership` SELECT * from `diva_groups_rolemembership`;
105DROP TABLE `diva_groups_rolemembership`;
106INSERT INTO `os_groups_invites` SELECT * from `diva_groups_invites`;
107DROP TABLE `diva_groups_invites`;
108INSERT INTO `os_groups_notices` SELECT * from `diva_groups_notices`;
109DROP TABLE `diva_groups_notices`;
110INSERT INTO `os_groups_principals` SELECT * from `diva_groups_principals`;
111DROP TABLE `diva_groups_principals`;
112
113DELETE FROM `migrations` WHERE name='diva_im_Store';
114
115COMMIT; \ 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/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Data/Null/NullXGroupData.cs
index d7198f0..7a86b9f 100644
--- a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs
+++ b/OpenSim/Data/Null/NullXGroupData.cs
@@ -26,66 +26,65 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenMetaverse; 29using System.Collections;
30using log4net; 30using System.Collections.Generic;
31using System.Linq;
31using System.Reflection; 32using System.Reflection;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
32using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Data;
33 38
34namespace OpenSim.Region.Framework.Scenes.Scripting 39namespace OpenSim.Data.Null
35{ 40{
36 public class NullScriptHost : IScriptHost 41 public class NullXGroupData : NullGenericDataHandler, IXGroupData
37 { 42 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39 44
40 private Vector3 m_pos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); 45 private Dictionary<UUID, XGroup> m_groups = new Dictionary<UUID, XGroup>();
41 46
42 public string Name 47 public NullXGroupData(string connectionString, string realm) {}
43 {
44 get { return "Object"; }
45 set { }
46 }
47 48
48 public string SitName 49 public bool StoreGroup(XGroup group)
49 { 50 {
50 get { return String.Empty; } 51 lock (m_groups)
51 set { } 52 {
52 } 53 m_groups[group.groupID] = group.Clone();
54 }
53 55
54 public string TouchName 56 return true;
55 {
56 get { return String.Empty; }
57 set { }
58 } 57 }
59 58
60 public string Description 59 public XGroup[] GetGroups(string field, string val)
61 { 60 {
62 get { return String.Empty; } 61 return GetGroups(new string[] { field }, new string[] { val });
63 set { }
64 } 62 }
65 63
66 public UUID UUID 64 public XGroup[] GetGroups(string[] fields, string[] vals)
67 { 65 {
68 get { return UUID.Zero; } 66 lock (m_groups)
69 } 67 {
68 List<XGroup> origGroups = Get<XGroup>(fields, vals, m_groups.Values.ToList());
70 69
71 public UUID OwnerID 70 return origGroups.Select(g => g.Clone()).ToArray();
72 { 71 }
73 get { return UUID.Zero; }
74 } 72 }
75 73
76 public UUID CreatorID 74 public bool DeleteGroups(string field, string val)
77 { 75 {
78 get { return UUID.Zero; } 76 return DeleteGroups(new string[] { field }, new string[] { val });
79 } 77 }
80 78
81 public Vector3 AbsolutePosition 79 public bool DeleteGroups(string[] fields, string[] vals)
82 { 80 {
83 get { return m_pos; } 81 lock (m_groups)
84 } 82 {
83 XGroup[] groupsToDelete = GetGroups(fields, vals);
84 Array.ForEach(groupsToDelete, g => m_groups.Remove(g.groupID));
85 }
85 86
86 public void SetText(string text, Vector3 color, double alpha) 87 return true;
87 {
88 m_log.Warn("Tried to SetText "+text+" on NullScriptHost");
89 } 88 }
90 } 89 }
91} 90} \ No newline at end of file
diff --git a/OpenSim/Data/Null/Properties/AssemblyInfo.cs b/OpenSim/Data/Null/Properties/AssemblyInfo.cs
index 43b0bb3..1e02c31 100644
--- a/OpenSim/Data/Null/Properties/AssemblyInfo.cs
+++ b/OpenSim/Data/Null/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Data/Properties/AssemblyInfo.cs b/OpenSim/Data/Properties/AssemblyInfo.cs
index 0da1a6b..a85f473 100644
--- a/OpenSim/Data/Properties/AssemblyInfo.cs
+++ b/OpenSim/Data/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs
index c9a8553..992982c 100644
--- a/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs
+++ b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations
index e872977..c6f4b48 100644
--- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations
+++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations
@@ -575,3 +575,20 @@ CREATE TABLE `regionenvironment` (
575); 575);
576 576
577COMMIT; 577COMMIT;
578
579:VERSION 27
580BEGIN;
581ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
582COMMIT;
583
584:VERSION 28
585
586BEGIN;
587
588ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
589ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
590ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
591ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
592ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
593
594COMMIT;
diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs
index b94a58c..82320ca 100644
--- a/OpenSim/Data/SQLite/SQLiteAssetData.cs
+++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs
@@ -46,7 +46,7 @@ namespace OpenSim.Data.SQLite
46 /// </summary> 46 /// </summary>
47 public class SQLiteAssetData : AssetDataBase 47 public class SQLiteAssetData : AssetDataBase
48 { 48 {
49// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 private const string SelectAssetSQL = "select * from assets where UUID=:UUID"; 51 private const string SelectAssetSQL = "select * from assets where UUID=:UUID";
52 private const string SelectAssetMetadataSQL = "select Name, Description, Type, Temporary, asset_flags, UUID, CreatorID from assets limit :start, :count"; 52 private const string SelectAssetMetadataSQL = "select Name, Description, Type, Temporary, asset_flags, UUID, CreatorID from assets limit :start, :count";
@@ -133,6 +133,24 @@ namespace OpenSim.Data.SQLite
133 /// <param name="asset">Asset Base</param> 133 /// <param name="asset">Asset Base</param>
134 override public bool StoreAsset(AssetBase asset) 134 override public bool StoreAsset(AssetBase asset)
135 { 135 {
136 string assetName = asset.Name;
137 if (asset.Name.Length > 64)
138 {
139 assetName = asset.Name.Substring(0, 64);
140 m_log.WarnFormat(
141 "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
142 asset.Name, asset.ID, asset.Name.Length, assetName.Length);
143 }
144
145 string assetDescription = asset.Description;
146 if (asset.Description.Length > 64)
147 {
148 assetDescription = asset.Description.Substring(0, 64);
149 m_log.WarnFormat(
150 "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
151 asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
152 }
153
136 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); 154 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString());
137 if (ExistsAsset(asset.FullID)) 155 if (ExistsAsset(asset.FullID))
138 { 156 {
@@ -143,8 +161,8 @@ namespace OpenSim.Data.SQLite
143 using (SqliteCommand cmd = new SqliteCommand(UpdateAssetSQL, m_conn)) 161 using (SqliteCommand cmd = new SqliteCommand(UpdateAssetSQL, m_conn))
144 { 162 {
145 cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString())); 163 cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString()));
146 cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name)); 164 cmd.Parameters.Add(new SqliteParameter(":Name", assetName));
147 cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description)); 165 cmd.Parameters.Add(new SqliteParameter(":Description", assetDescription));
148 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type)); 166 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type));
149 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local)); 167 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local));
150 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary)); 168 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary));
@@ -164,8 +182,8 @@ namespace OpenSim.Data.SQLite
164 using (SqliteCommand cmd = new SqliteCommand(InsertAssetSQL, m_conn)) 182 using (SqliteCommand cmd = new SqliteCommand(InsertAssetSQL, m_conn))
165 { 183 {
166 cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString())); 184 cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString()));
167 cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name)); 185 cmd.Parameters.Add(new SqliteParameter(":Name", assetName));
168 cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description)); 186 cmd.Parameters.Add(new SqliteParameter(":Description", assetDescription));
169 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type)); 187 cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type));
170 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local)); 188 cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local));
171 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary)); 189 cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary));
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index 42cd59d..99a6598 100644
--- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs
+++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
@@ -1232,6 +1232,14 @@ namespace OpenSim.Data.SQLite
1232 createCol(prims, "VolumeDetect", typeof(Int16)); 1232 createCol(prims, "VolumeDetect", typeof(Int16));
1233 1233
1234 createCol(prims, "MediaURL", typeof(String)); 1234 createCol(prims, "MediaURL", typeof(String));
1235
1236 createCol(prims, "DynAttrs", typeof(String));
1237
1238 createCol(prims, "PhysicsShapeType", typeof(Byte));
1239 createCol(prims, "Density", typeof(Double));
1240 createCol(prims, "GravityModifier", typeof(Double));
1241 createCol(prims, "Friction", typeof(Double));
1242 createCol(prims, "Restitution", typeof(Double));
1235 1243
1236 // Add in contraints 1244 // Add in contraints
1237 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; 1245 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
@@ -1711,6 +1719,22 @@ namespace OpenSim.Data.SQLite
1711// m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType()); 1719// m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType());
1712 prim.MediaUrl = (string)row["MediaURL"]; 1720 prim.MediaUrl = (string)row["MediaURL"];
1713 } 1721 }
1722
1723 if (!(row["DynAttrs"] is System.DBNull))
1724 {
1725 //m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType());
1726 prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]);
1727 }
1728 else
1729 {
1730 prim.DynAttrs = new DAMap();
1731 }
1732
1733 prim.PhysicsShapeType = Convert.ToByte(row["PhysicsShapeType"]);
1734 prim.Density = Convert.ToSingle(row["Density"]);
1735 prim.GravityModifier = Convert.ToSingle(row["GravityModifier"]);
1736 prim.Friction = Convert.ToSingle(row["Friction"]);
1737 prim.Restitution = Convert.ToSingle(row["Restitution"]);
1714 1738
1715 return prim; 1739 return prim;
1716 } 1740 }
@@ -2133,6 +2157,17 @@ namespace OpenSim.Data.SQLite
2133 row["VolumeDetect"] = 0; 2157 row["VolumeDetect"] = 0;
2134 2158
2135 row["MediaURL"] = prim.MediaUrl; 2159 row["MediaURL"] = prim.MediaUrl;
2160
2161 if (prim.DynAttrs.Count > 0)
2162 row["DynAttrs"] = prim.DynAttrs.ToXml();
2163 else
2164 row["DynAttrs"] = null;
2165
2166 row["PhysicsShapeType"] = prim.PhysicsShapeType;
2167 row["Density"] = (double)prim.Density;
2168 row["GravityModifier"] = (double)prim.GravityModifier;
2169 row["Friction"] = (double)prim.Friction;
2170 row["Restitution"] = (double)prim.Restitution;
2136 } 2171 }
2137 2172
2138 /// <summary> 2173 /// <summary>
@@ -2392,7 +2427,7 @@ namespace OpenSim.Data.SQLite
2392 2427
2393 if (!(row["Media"] is System.DBNull)) 2428 if (!(row["Media"] is System.DBNull))
2394 s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); 2429 s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]);
2395 2430
2396 return s; 2431 return s;
2397 } 2432 }
2398 2433
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/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs
index 02986d5..d6b4e6a 100644
--- a/OpenSim/Framework/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssemblyInfo.cs
@@ -59,5 +59,4 @@ using System.Runtime.InteropServices;
59// Revision 59// Revision
60// 60//
61 61
62[assembly : AssemblyVersion("0.7.5.*")] 62[assembly : AssemblyVersion("0.7.6.*")]
63[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file
diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
index 0498ed4..feffa26 100644
--- a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 041fb94..b7a0adf 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -497,8 +497,6 @@ namespace OpenSim.Framework
497 /// </remarks> 497 /// </remarks>
498 public List<AvatarAttachment> GetAttachments() 498 public List<AvatarAttachment> GetAttachments()
499 { 499 {
500
501
502 lock (m_attachments) 500 lock (m_attachments)
503 { 501 {
504 List<AvatarAttachment> alist = new List<AvatarAttachment>(); 502 List<AvatarAttachment> alist = new List<AvatarAttachment>();
@@ -508,7 +506,8 @@ namespace OpenSim.Framework
508 alist.Add(new AvatarAttachment(attach)); 506 alist.Add(new AvatarAttachment(attach));
509 } 507 }
510 return alist; 508 return alist;
511 } } 509 }
510 }
512 511
513 internal void AppendAttachment(AvatarAttachment attach) 512 internal void AppendAttachment(AvatarAttachment attach)
514 { 513 {
@@ -562,45 +561,59 @@ namespace OpenSim.Framework
562 if (attachpoint == 0) 561 if (attachpoint == 0)
563 return false; 562 return false;
564 563
565 if (item == UUID.Zero) 564 lock (m_attachments)
566 { 565 {
567 lock (m_attachments) 566 if (item == UUID.Zero)
568 { 567 {
569 if (m_attachments.ContainsKey(attachpoint)) 568 if (m_attachments.ContainsKey(attachpoint))
570 { 569 {
571 m_attachments.Remove(attachpoint); 570 m_attachments.Remove(attachpoint);
572 return true; 571 return true;
573 } 572 }
573
574 return false;
574 } 575 }
575
576 return false;
577 }
578 576
579 // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, 577 // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
580 // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If 578 // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
581 // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments 579 // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
582 // later fail unless the attachment is detached and reattached. 580 // later fail unless the attachment is detached and reattached.
583 // 581 //
584 // Therefore, we will carry on with the set if the existing attachment has no asset id. 582 // Therefore, we will carry on with the set if the existing attachment has no asset id.
585 AvatarAttachment existingAttachment = GetAttachmentForItem(item); 583 AvatarAttachment existingAttachment = GetAttachmentForItem(item);
586 if (existingAttachment != null 584 if (existingAttachment != null)
587 && existingAttachment.AssetID != UUID.Zero 585 {
588 && existingAttachment.AttachPoint == (attachpoint & 0x7F)) 586// m_log.DebugFormat(
589 { 587// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
590 // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item); 588// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
591 return false; 589
592 } 590 if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
593 591 {
594 // check if this is an append or a replace, 0x80 marks it as an append 592 m_log.DebugFormat(
595 if ((attachpoint & 0x80) > 0) 593 "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
596 { 594 item, attachpoint);
597 // strip the append bit 595
598 int point = attachpoint & 0x7F; 596 return false;
599 AppendAttachment(new AvatarAttachment(point, item, asset)); 597 }
600 } 598 else
601 else 599 {
602 { 600 // Remove it here so that the later append does not add a second attachment but we still update
603 ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); 601 // the assetID
602 DetachAttachment(existingAttachment.ItemID);
603 }
604 }
605
606 // check if this is an append or a replace, 0x80 marks it as an append
607 if ((attachpoint & 0x80) > 0)
608 {
609 // strip the append bit
610 int point = attachpoint & 0x7F;
611 AppendAttachment(new AvatarAttachment(point, item, asset));
612 }
613 else
614 {
615 ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
616 }
604 } 617 }
605 618
606 return true; 619 return true;
@@ -649,6 +662,10 @@ namespace OpenSim.Framework
649 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); 662 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
650 if (index >= 0) 663 if (index >= 0)
651 { 664 {
665// m_log.DebugFormat(
666// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
667// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
668
652 // Remove it from the list of attachments at that attach point 669 // Remove it from the list of attachments at that attach point
653 m_attachments[kvp.Key].RemoveAt(index); 670 m_attachments[kvp.Key].RemoveAt(index);
654 671
diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
index 6d1c03a..df8eb52 100644
--- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65
diff --git a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs b/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
index 3dce578..6681c37 100644
--- a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
+++ b/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
@@ -65,23 +65,27 @@ namespace OpenSim.Framework.Configuration.HTTP
65 byte[] buf = new byte[8192]; 65 byte[] buf = new byte[8192];
66 HttpWebRequest request = 66 HttpWebRequest request =
67 (HttpWebRequest) WebRequest.Create(remoteConfigSettings.baseConfigURL + configFileName); 67 (HttpWebRequest) WebRequest.Create(remoteConfigSettings.baseConfigURL + configFileName);
68 HttpWebResponse response = (HttpWebResponse) request.GetResponse(); 68 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
69
70 Stream resStream = response.GetResponseStream();
71
72 string tempString = null;
73 int count = 0;
74
75 do
76 { 69 {
77 count = resStream.Read(buf, 0, buf.Length); 70 using (Stream resStream = response.GetResponseStream())
78 if (count != 0)
79 { 71 {
80 tempString = Util.UTF8.GetString(buf, 0, count); 72 string tempString = null;
81 sb.Append(tempString); 73 int count = 0;
74
75 do
76 {
77 count = resStream.Read(buf, 0, buf.Length);
78 if (count != 0)
79 {
80 tempString = Util.UTF8.GetString(buf, 0, count);
81 sb.Append(tempString);
82 }
83 }
84 while (count > 0);
85
86 LoadDataFromString(sb.ToString());
82 } 87 }
83 } while (count > 0); 88 }
84 LoadDataFromString(sb.ToString());
85 } 89 }
86 catch (WebException) 90 catch (WebException)
87 { 91 {
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
index 0674656..3ef9682 100644
--- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
index 1095b23..cbdffeb 100644
--- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/Console/AssemblyInfo.cs b/OpenSim/Framework/Console/AssemblyInfo.cs
index 37c7304..c618454 100644
--- a/OpenSim/Framework/Console/AssemblyInfo.cs
+++ b/OpenSim/Framework/Console/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
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..97a86a8 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -49,14 +49,14 @@ namespace OpenSim.Framework.Console
49 = @"Each component of the coord is comma separated. There must be no spaces between the commas. 49 = @"Each component of the coord is comma separated. There must be no spaces between the commas.
50 If you don't care about the z component you can simply omit it. 50 If you don't care about the z component you can simply omit it.
51 If you don't care about the x or y components then you can leave them blank (though a comma is still required) 51 If you don't care about the x or y components then you can leave them blank (though a comma is still required)
52 If you want to specify the maxmimum value of a component then you can use ~ instead of a number 52 If you want to specify the maximum value of a component then you can use ~ instead of a number
53 If you want to specify the minimum value of a component then you can use -~ instead of a number 53 If you want to specify the minimum value of a component then you can use -~ instead of a number
54 e.g. 54 e.g.
55 delete object pos 20,20,20 to 40,40,40 55 show object pos 20,20,20 to 40,40,40
56 delete object pos 20,20 to 40,40 56 delete object pos 20,20 to 40,40
57 delete object pos ,20,20 to ,40,40 57 show object pos ,20,20 to ,40,40
58 delete object pos ,,30 to ,,~ 58 delete object pos ,,30 to ,,~
59 delete object pos ,,-~ to ,,30"; 59 show object pos ,,-~ to ,,30";
60 60
61 public const string MinRawConsoleVectorValue = "-~"; 61 public const string MinRawConsoleVectorValue = "-~";
62 public const string MaxRawConsoleVectorValue = "~"; 62 public const string MaxRawConsoleVectorValue = "~";
@@ -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/DAMap.cs b/OpenSim/Framework/DAMap.cs
new file mode 100644
index 0000000..df4a6bc
--- /dev/null
+++ b/OpenSim/Framework/DAMap.cs
@@ -0,0 +1,273 @@
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.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Schema;
35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38
39namespace OpenSim.Framework
40{
41 /// <summary>
42 /// This class stores and retrieves dynamic attributes.
43 /// </summary>
44 /// <remarks>
45 /// Modules that want to use dynamic attributes need to do so in a private data store
46 /// which is accessed using a unique name. DAMap provides access to the data stores,
47 /// each of which is an OSDMap. Modules are free to store any type of data they want
48 /// within their data store. However, avoid storing large amounts of data because that
49 /// would slow down database access.
50 /// </remarks>
51 public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable
52 {
53 private static readonly int MIN_STORE_NAME_LENGTH = 4;
54
55 protected OSDMap m_map;
56
57 public DAMap() { m_map = new OSDMap(); }
58
59 public XmlSchema GetSchema() { return null; }
60
61 public static DAMap FromXml(string rawXml)
62 {
63 DAMap map = new DAMap();
64 map.ReadXml(rawXml);
65 return map;
66 }
67
68 public void ReadXml(string rawXml)
69 {
70 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
71
72 lock (this)
73 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
74 }
75
76 // WARNING: this is temporary for experimentation only, it will be removed!!!!
77 public OSDMap TopLevelMap
78 {
79 get { return m_map; }
80 set { m_map = value; }
81 }
82
83
84 public void ReadXml(XmlReader reader)
85 {
86 ReadXml(reader.ReadInnerXml());
87 }
88
89 public string ToXml()
90 {
91 lock (this)
92 return OSDParser.SerializeLLSDXmlString(m_map);
93 }
94
95 public void WriteXml(XmlWriter writer)
96 {
97 writer.WriteRaw(ToXml());
98 }
99
100 public void CopyFrom(DAMap other)
101 {
102 // Deep copy
103
104 string data = null;
105 lock (other)
106 {
107 if (other.Count > 0)
108 {
109 data = OSDParser.SerializeLLSDXmlString(other.m_map);
110 }
111 }
112
113 lock (this)
114 {
115 if (data == null)
116 Clear();
117 else
118 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data);
119 }
120 }
121
122 /// <summary>
123 /// Returns the number of data stores.
124 /// </summary>
125 public int Count { get { lock (this) { return m_map.Count; } } }
126
127 public bool IsReadOnly { get { return false; } }
128
129 /// <summary>
130 /// Returns the names of the data stores.
131 /// </summary>
132 public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } }
133
134 /// <summary>
135 /// Returns all the data stores.
136 /// </summary>
137 public ICollection<OSDMap> Values
138 {
139 get
140 {
141 lock (this)
142 {
143 List<OSDMap> stores = new List<OSDMap>(m_map.Count);
144 foreach (OSD llsd in m_map.Values)
145 stores.Add((OSDMap)llsd);
146 return stores;
147 }
148 }
149 }
150
151 /// <summary>
152 /// Gets or sets one data store.
153 /// </summary>
154 /// <param name="key">Store name</param>
155 /// <returns></returns>
156 public OSDMap this[string key]
157 {
158 get
159 {
160 OSD llsd;
161
162 lock (this)
163 {
164 if (m_map.TryGetValue(key, out llsd))
165 return (OSDMap)llsd;
166 else
167 return null;
168 }
169 }
170
171 set
172 {
173 ValidateKey(key);
174 lock (this)
175 m_map[key] = value;
176 }
177 }
178
179 /// <summary>
180 /// Validate the key used for storing separate data stores.
181 /// </summary>
182 /// <param name='key'></param>
183 public static void ValidateKey(string key)
184 {
185 if (key.Length < MIN_STORE_NAME_LENGTH)
186 throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
187 }
188
189 public bool ContainsKey(string key)
190 {
191 lock (this)
192 return m_map.ContainsKey(key);
193 }
194
195 public void Add(string key, OSDMap store)
196 {
197 ValidateKey(key);
198 lock (this)
199 m_map.Add(key, store);
200 }
201
202 public void Add(KeyValuePair<string, OSDMap> kvp)
203 {
204 ValidateKey(kvp.Key);
205 lock (this)
206 m_map.Add(kvp.Key, kvp.Value);
207 }
208
209 public bool Remove(string key)
210 {
211 lock (this)
212 return m_map.Remove(key);
213 }
214
215 public bool TryGetValue(string key, out OSDMap store)
216 {
217 lock (this)
218 {
219 OSD llsd;
220 if (m_map.TryGetValue(key, out llsd))
221 {
222 store = (OSDMap)llsd;
223 return true;
224 }
225 else
226 {
227 store = null;
228 return false;
229 }
230 }
231 }
232
233 public void Clear()
234 {
235 lock (this)
236 m_map.Clear();
237 }
238
239 public bool Contains(KeyValuePair<string, OSDMap> kvp)
240 {
241 lock (this)
242 return m_map.ContainsKey(kvp.Key);
243 }
244
245 public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index)
246 {
247 throw new NotImplementedException();
248 }
249
250 public bool Remove(KeyValuePair<string, OSDMap> kvp)
251 {
252 lock (this)
253 return m_map.Remove(kvp.Key);
254 }
255
256 public System.Collections.IDictionaryEnumerator GetEnumerator()
257 {
258 lock (this)
259 return m_map.GetEnumerator();
260 }
261
262 IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator()
263 {
264 return null;
265 }
266
267 IEnumerator IEnumerable.GetEnumerator()
268 {
269 lock (this)
270 return m_map.GetEnumerator();
271 }
272 }
273} \ No newline at end of file
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/Framework/DOMap.cs
index 02ef588..755e129 100644
--- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs
+++ b/OpenSim/Framework/DOMap.cs
@@ -26,69 +26,73 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Schema;
29using System.Xml.Serialization; 35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
30 38
31namespace OpenSim.ApplicationPlugins.Rest.Regions 39namespace OpenSim.Framework
32{ 40{
33 public partial class RestRegionPlugin : RestPlugin 41 /// <summary>
42 /// This class stores and retrieves dynamic objects.
43 /// </summary>
44 /// <remarks>
45 /// Experimental - DO NOT USE.
46 /// </remarks>
47 public class DOMap
34 { 48 {
35 private static XmlSerializerNamespaces _xmlNs; 49 private IDictionary<string, object> m_map;
36 50
37 static RestRegionPlugin() 51 public void Add(string key, object dynObj)
38 { 52 {
39 _xmlNs = new XmlSerializerNamespaces(); 53 DAMap.ValidateKey(key);
40 _xmlNs.Add(String.Empty, String.Empty);
41 }
42 54
43 #region overriding properties 55 lock (this)
44 public override string Name 56 {
45 { 57 if (m_map == null)
46 get { return "REGION"; } 58 m_map = new Dictionary<string, object>();
59
60 m_map.Add(key, dynObj);
61 }
47 } 62 }
48 63
49 public override string ConfigName 64 public bool ContainsKey(string key)
50 { 65 {
51 get { return "RestRegionPlugin"; } 66 return Get(key) != null;
52 } 67 }
53 #endregion overriding properties
54 68
55 #region overriding methods
56 /// <summary> 69 /// <summary>
57 /// This method is called by OpenSimMain immediately after loading the 70 /// Get a dynamic object
58 /// plugin and after basic server setup, but before running any server commands.
59 /// </summary> 71 /// </summary>
60 /// <remarks> 72 /// <remarks>
61 /// Note that entries MUST be added to the active configuration files before 73 /// Not providing an index method so that users can't casually overwrite each other's objects.
62 /// the plugin can be enabled.
63 /// </remarks> 74 /// </remarks>
64 public override void Initialise(OpenSimBase openSim) 75 /// <param name='key'></param>
76 public object Get(string key)
65 { 77 {
66 try 78 lock (this)
67 { 79 {
68 base.Initialise(openSim); 80 if (m_map == null)
69 if (!IsEnabled) 81 return null;
70 { 82 else
71 //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); 83 return m_map[key];
72 return;
73 }
74
75 m_log.InfoFormat("{0} REST region plugin enabled", MsgID);
76
77 // add REST method handlers
78 AddRestStreamHandler("GET", "/regions/", GetHandler);
79 AddRestStreamHandler("POST", "/regions/", PostHandler);
80 AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler);
81 }
82 catch (Exception e)
83 {
84 m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
85 m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
86 } 84 }
87 } 85 }
88 86
89 public override void Close() 87 public bool Remove(string key)
90 { 88 {
89 lock (this)
90 {
91 if (m_map == null)
92 return false;
93 else
94 return m_map.Remove(key);
95 }
91 } 96 }
92 #endregion overriding methods
93 } 97 }
94} 98} \ No newline at end of file
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/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 0465042..c88828b 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -320,7 +320,7 @@ namespace OpenSim.Framework
320 public delegate void ObjectPermissions( 320 public delegate void ObjectPermissions(
321 IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set); 321 IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set);
322 322
323 public delegate void EconomyDataRequest(UUID agentID); 323 public delegate void EconomyDataRequest(IClientAPI client);
324 324
325 public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID); 325 public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID);
326 326
@@ -1129,8 +1129,8 @@ namespace OpenSim.Framework
1129 1129
1130 void SendInstantMessage(GridInstantMessage im); 1130 void SendInstantMessage(GridInstantMessage im);
1131 1131
1132 void SendGenericMessage(string method, List<string> message); 1132 void SendGenericMessage(string method, UUID invoice, List<string> message);
1133 void SendGenericMessage(string method, List<byte[]> message); 1133 void SendGenericMessage(string method, UUID invoice, List<byte[]> message);
1134 1134
1135 void SendLayerData(float[] map); 1135 void SendLayerData(float[] map);
1136 void SendLayerData(int px, int py, float[] map); 1136 void SendLayerData(int px, int py, float[] map);
diff --git a/OpenSim/Framework/ILandChannel.cs b/OpenSim/Framework/ILandChannel.cs
index 869d4c8..c46c03c 100644
--- a/OpenSim/Framework/ILandChannel.cs
+++ b/OpenSim/Framework/ILandChannel.cs
@@ -56,6 +56,13 @@ namespace OpenSim.Region.Framework.Interfaces
56 ILandObject GetLandObject(float x, float y); 56 ILandObject GetLandObject(float x, float y);
57 57
58 /// <summary> 58 /// <summary>
59 /// Get the parcel at the specified point
60 /// </summary>
61 /// <param name="position">Vector where x and y components are between 0 and 256. z component is ignored.</param>
62 /// <returns>Land object at the point supplied</returns>
63 ILandObject GetLandObject(Vector3 position);
64
65 /// <summary>
59 /// Get the parcels near the specified point 66 /// Get the parcels near the specified point
60 /// </summary> 67 /// </summary>
61 /// <param name="position"></param> 68 /// <param name="position"></param>
diff --git a/OpenSim/Framework/Monitoring/AssetStatsCollector.cs b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
index 2a4d45b..6a0f676 100644
--- a/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
@@ -28,6 +28,8 @@
28using System; 28using System;
29using System.Timers; 29using System.Timers;
30 30
31using OpenMetaverse.StructuredData;
32
31namespace OpenSim.Framework.Monitoring 33namespace OpenSim.Framework.Monitoring
32{ 34{
33 /// <summary> 35 /// <summary>
@@ -100,5 +102,29 @@ Asset requests yesterday : {3} ({4} per hour) of which {5} were not found",
100 AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday, 102 AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday,
101 AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday); 103 AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday);
102 } 104 }
105
106 public override string XReport(string uptime, string version)
107 {
108 return OSDParser.SerializeJsonString(OReport(uptime, version));
109 }
110
111 public override OSDMap OReport(string uptime, string version)
112 {
113 double elapsedHours = (DateTime.Now - startTime).TotalHours;
114 if (elapsedHours <= 0) { elapsedHours = 1; } // prevent divide by zero
115
116 long assetRequestsTodayPerHour = (long)Math.Round(AssetRequestsToday / elapsedHours);
117 long assetRequestsYesterdayPerHour = (long)Math.Round(AssetRequestsYesterday / 24.0);
118
119 OSDMap ret = new OSDMap();
120 ret.Add("AssetRequestsToday", OSD.FromLong(AssetRequestsToday));
121 ret.Add("AssetRequestsTodayPerHour", OSD.FromLong(assetRequestsTodayPerHour));
122 ret.Add("AssetRequestsNotFoundToday", OSD.FromLong(AssetRequestsNotFoundToday));
123 ret.Add("AssetRequestsYesterday", OSD.FromLong(AssetRequestsYesterday));
124 ret.Add("AssetRequestsYesterdayPerHour", OSD.FromLong(assetRequestsYesterdayPerHour));
125 ret.Add("AssetRequestsNotFoundYesterday", OSD.FromLong(assetRequestsNotFoundYesterday));
126
127 return ret;
128 }
103 } 129 }
104} 130}
diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
index 446e3c0..23dba09 100644
--- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
@@ -80,5 +80,12 @@ namespace OpenSim.Framework.Monitoring
80 { 80 {
81 return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ; 81 return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ;
82 } 82 }
83
84 public virtual OSDMap OReport(string uptime, string version)
85 {
86 OSDMap ret = new OSDMap();
87 ret.Add("TotalMemory", new OSDReal(Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)));
88 return ret;
89 }
83 } 90 }
84} 91}
diff --git a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
index 99f75e3..40df562 100644
--- a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
@@ -25,6 +25,8 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenMetaverse.StructuredData;
29
28namespace OpenSim.Framework.Monitoring 30namespace OpenSim.Framework.Monitoring
29{ 31{
30 /// <summary> 32 /// <summary>
@@ -45,5 +47,12 @@ namespace OpenSim.Framework.Monitoring
45 /// A <see cref="System.String"/> 47 /// A <see cref="System.String"/>
46 /// </returns> 48 /// </returns>
47 string XReport(string uptime, string version); 49 string XReport(string uptime, string version);
50
51 /// <summary>
52 /// Report back collected statistical information as an OSDMap of key/values
53 /// </summary>
54 /// <returns>
55 /// </returns>
56 OSDMap OReport(string uptime, string version);
48 } 57 }
49} 58}
diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
index 1f2bb40..36678bb 100644
--- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index aa86202..6a68322 100644
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -359,11 +359,12 @@ Asset service request failures: {3}" + Environment.NewLine,
359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, 359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); 360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361 361
362 Dictionary<string, Dictionary<string, Stat>> sceneStats; 362 /* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
363 363 * the two formatted printouts above.
364 SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
364 if (StatsManager.TryGetStats("scene", out sceneStats)) 365 if (StatsManager.TryGetStats("scene", out sceneStats))
365 { 366 {
366 foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats) 367 foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
367 { 368 {
368 foreach (Stat stat in kvp.Value.Values) 369 foreach (Stat stat in kvp.Value.Values)
369 { 370 {
@@ -374,6 +375,7 @@ Asset service request failures: {3}" + Environment.NewLine,
374 } 375 }
375 } 376 }
376 } 377 }
378 */
377 379
378 /* 380 /*
379 sb.Append(Environment.NewLine); 381 sb.Append(Environment.NewLine);
@@ -405,6 +407,15 @@ Asset service request failures: {3}" + Environment.NewLine,
405 /// <returns></returns> 407 /// <returns></returns>
406 public override string XReport(string uptime, string version) 408 public override string XReport(string uptime, string version)
407 { 409 {
410 return OSDParser.SerializeJsonString(OReport(uptime, version));
411 }
412
413 /// <summary>
414 /// Report back collected statistical information as an OSDMap
415 /// </summary>
416 /// <returns></returns>
417 public override OSDMap OReport(string uptime, string version)
418 {
408 OSDMap args = new OSDMap(30); 419 OSDMap args = new OSDMap(30);
409// args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache)); 420// args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache));
410// args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}", 421// args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}",
@@ -442,13 +453,11 @@ Asset service request failures: {3}" + Environment.NewLine,
442 args["Uptime"] = OSD.FromString (uptime); 453 args["Uptime"] = OSD.FromString (uptime);
443 args["Version"] = OSD.FromString (version); 454 args["Version"] = OSD.FromString (version);
444 455
445 string strBuffer = ""; 456 return args;
446 strBuffer = OSDParser.SerializeJsonString(args);
447
448 return strBuffer;
449 } 457 }
450 } 458 }
451 459
460
452 /// <summary> 461 /// <summary>
453 /// Pull packet queue stats from packet queues and report 462 /// Pull packet queue stats from packet queues and report
454 /// </summary> 463 /// </summary>
@@ -474,5 +483,11 @@ Asset service request failures: {3}" + Environment.NewLine,
474 { 483 {
475 return ""; 484 return "";
476 } 485 }
486
487 public OSDMap OReport(string uptime, string version)
488 {
489 OSDMap ret = new OSDMap();
490 return ret;
491 }
477 } 492 }
478} 493}
diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
new file mode 100755
index 0000000..caea30d
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
@@ -0,0 +1,228 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenMetaverse.StructuredData;
34
35namespace OpenSim.Framework.Monitoring
36{
37// Create a time histogram of events. The histogram is built in a wrap-around
38// array of equally distributed buckets.
39// For instance, a minute long histogram of second sized buckets would be:
40// new EventHistogram(60, 1000)
41public class EventHistogram
42{
43 private int m_timeBase;
44 private int m_numBuckets;
45 private int m_bucketMilliseconds;
46 private int m_lastBucket;
47 private int m_totalHistogramMilliseconds;
48 private long[] m_histogram;
49 private object histoLock = new object();
50
51 public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
52 {
53 m_numBuckets = numberOfBuckets;
54 m_bucketMilliseconds = millisecondsPerBucket;
55 m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
56
57 m_histogram = new long[m_numBuckets];
58 Zero();
59 m_lastBucket = 0;
60 m_timeBase = Util.EnvironmentTickCount();
61 }
62
63 public void Event()
64 {
65 this.Event(1);
66 }
67
68 // Record an event at time 'now' in the histogram.
69 public void Event(int cnt)
70 {
71 lock (histoLock)
72 {
73 // The time as displaced from the base of the histogram
74 int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
75
76 // If more than the total time of the histogram, we just start over
77 if (bucketTime > m_totalHistogramMilliseconds)
78 {
79 Zero();
80 m_lastBucket = 0;
81 m_timeBase = Util.EnvironmentTickCount();
82 }
83 else
84 {
85 // To which bucket should we add this event?
86 int bucket = bucketTime / m_bucketMilliseconds;
87
88 // Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
89 while (bucket != m_lastBucket)
90 {
91 // Zero from just after the last bucket to the new bucket or the end
92 for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
93 {
94 m_histogram[jj] = 0;
95 }
96 m_lastBucket = bucket;
97 // If the new bucket is off the end, wrap around to the beginning
98 if (bucket > m_numBuckets)
99 {
100 bucket -= m_numBuckets;
101 m_lastBucket = 0;
102 m_histogram[m_lastBucket] = 0;
103 m_timeBase += m_totalHistogramMilliseconds;
104 }
105 }
106 }
107 m_histogram[m_lastBucket] += cnt;
108 }
109 }
110
111 // Get a copy of the current histogram
112 public long[] GetHistogram()
113 {
114 long[] ret = new long[m_numBuckets];
115 lock (histoLock)
116 {
117 int indx = m_lastBucket + 1;
118 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
119 {
120 if (indx >= m_numBuckets)
121 indx = 0;
122 ret[ii] = m_histogram[indx];
123 }
124 }
125 return ret;
126 }
127
128 public OSDMap GetHistogramAsOSDMap()
129 {
130 OSDMap ret = new OSDMap();
131
132 ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
133 ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
134 ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
135
136 // Compute a number for the first bucket in the histogram.
137 // This will allow readers to know how this histogram relates to any previously read histogram.
138 int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
139 ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
140
141 ret.Add("Values", GetHistogramAsOSDArray());
142
143 return ret;
144 }
145 // Get a copy of the current histogram
146 public OSDArray GetHistogramAsOSDArray()
147 {
148 OSDArray ret = new OSDArray(m_numBuckets);
149 lock (histoLock)
150 {
151 int indx = m_lastBucket + 1;
152 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
153 {
154 if (indx >= m_numBuckets)
155 indx = 0;
156 ret[ii] = OSD.FromLong(m_histogram[indx]);
157 }
158 }
159 return ret;
160 }
161
162 // Zero out the histogram
163 public void Zero()
164 {
165 lock (histoLock)
166 {
167 for (int ii = 0; ii < m_numBuckets; ii++)
168 m_histogram[ii] = 0;
169 }
170 }
171}
172
173// A statistic that wraps a counter.
174// Built this way mostly so histograms and history can be created.
175public class CounterStat : Stat
176{
177 private SortedDictionary<string, EventHistogram> m_histograms;
178 private object counterLock = new object();
179
180 public CounterStat(
181 string shortName,
182 string name,
183 string description,
184 string unitName,
185 string category,
186 string container,
187 StatVerbosity verbosity)
188 : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity)
189 {
190 m_histograms = new SortedDictionary<string, EventHistogram>();
191 }
192
193 // Histograms are presumably added at intialization time and the list does not change thereafter.
194 // Thus no locking of the histogram list.
195 public void AddHistogram(string histoName, EventHistogram histo)
196 {
197 m_histograms.Add(histoName, histo);
198 }
199
200 public delegate void ProcessHistogram(string name, EventHistogram histo);
201 public void ForEachHistogram(ProcessHistogram process)
202 {
203 foreach (KeyValuePair<string, EventHistogram> kvp in m_histograms)
204 {
205 process(kvp.Key, kvp.Value);
206 }
207 }
208
209 public void Event()
210 {
211 this.Event(1);
212 }
213
214 // Count the underlying counter.
215 public void Event(int cnt)
216 {
217 lock (counterLock)
218 {
219 base.Value += cnt;
220
221 foreach (EventHistogram histo in m_histograms.Values)
222 {
223 histo.Event(cnt);
224 }
225 }
226 }
227}
228}
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs
index f91251b..2e7665f 100644
--- a/OpenSim/Framework/Monitoring/Stats/Stat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs
@@ -29,12 +29,14 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenMetaverse.StructuredData;
33
32namespace OpenSim.Framework.Monitoring 34namespace OpenSim.Framework.Monitoring
33{ 35{
34 /// <summary> 36 /// <summary>
35 /// Holds individual statistic details 37 /// Holds individual statistic details
36 /// </summary> 38 /// </summary>
37 public class Stat 39 public class Stat : IDisposable
38 { 40 {
39 /// <summary> 41 /// <summary>
40 /// Category of this stat (e.g. cache, scene, etc). 42 /// Category of this stat (e.g. cache, scene, etc).
@@ -181,6 +183,12 @@ namespace OpenSim.Framework.Monitoring
181 Verbosity = verbosity; 183 Verbosity = verbosity;
182 } 184 }
183 185
186 // IDisposable.Dispose()
187 public virtual void Dispose()
188 {
189 return;
190 }
191
184 /// <summary> 192 /// <summary>
185 /// Record a value in the sample set. 193 /// Record a value in the sample set.
186 /// </summary> 194 /// </summary>
@@ -203,13 +211,27 @@ namespace OpenSim.Framework.Monitoring
203 public virtual string ToConsoleString() 211 public virtual string ToConsoleString()
204 { 212 {
205 StringBuilder sb = new StringBuilder(); 213 StringBuilder sb = new StringBuilder();
206 sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName); 214 sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName);
207 215
208 AppendMeasuresOfInterest(sb); 216 AppendMeasuresOfInterest(sb);
209 217
210 return sb.ToString(); 218 return sb.ToString();
211 } 219 }
212 220
221 public virtual OSDMap ToOSDMap()
222 {
223 OSDMap ret = new OSDMap();
224 ret.Add("Category", OSD.FromString(Category));
225 ret.Add("Container", OSD.FromString(Container));
226 ret.Add("ShortName", OSD.FromString(ShortName));
227 ret.Add("Name", OSD.FromString(Name));
228 ret.Add("Description", OSD.FromString(Description));
229 ret.Add("UnitName", OSD.FromString(UnitName));
230 ret.Add("Value", OSD.FromReal(Value));
231
232 return ret;
233 }
234
213 protected void AppendMeasuresOfInterest(StringBuilder sb) 235 protected void AppendMeasuresOfInterest(StringBuilder sb)
214 { 236 {
215 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) 237 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 0762b01..24db6d4 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -51,8 +51,8 @@ namespace OpenSim.Framework.Monitoring
51 /// <remarks> 51 /// <remarks>
52 /// Do not add or remove directly from this dictionary. 52 /// Do not add or remove directly from this dictionary.
53 /// </remarks> 53 /// </remarks>
54 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats 54 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats
55 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>(); 55 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>();
56 56
57 private static AssetStatsCollector assetStats; 57 private static AssetStatsCollector assetStats;
58 private static UserStatsCollector userStats; 58 private static UserStatsCollector userStats;
@@ -85,6 +85,7 @@ namespace OpenSim.Framework.Monitoring
85 if (cmd.Length > 2) 85 if (cmd.Length > 2)
86 { 86 {
87 var categoryName = cmd[2]; 87 var categoryName = cmd[2];
88 var containerName = cmd.Length > 3 ? cmd[3] : String.Empty;
88 89
89 if (categoryName == AllSubCommand) 90 if (categoryName == AllSubCommand)
90 { 91 {
@@ -101,14 +102,27 @@ namespace OpenSim.Framework.Monitoring
101 } 102 }
102 else 103 else
103 { 104 {
104 Dictionary<string, Dictionary<string, Stat>> category; 105 SortedDictionary<string, SortedDictionary<string, Stat>> category;
105 if (!RegisteredStats.TryGetValue(categoryName, out category)) 106 if (!RegisteredStats.TryGetValue(categoryName, out category))
106 { 107 {
107 con.OutputFormat("No such category as {0}", categoryName); 108 con.OutputFormat("No such category as {0}", categoryName);
108 } 109 }
109 else 110 else
110 { 111 {
111 OutputCategoryStatsToConsole(con, category); 112 if (String.IsNullOrEmpty(containerName))
113 OutputCategoryStatsToConsole(con, category);
114 else
115 {
116 SortedDictionary<string, Stat> container;
117 if (category.TryGetValue(containerName, out container))
118 {
119 OutputContainerStatsToConsole(con, container);
120 }
121 else
122 {
123 con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
124 }
125 }
112 } 126 }
113 } 127 }
114 } 128 }
@@ -120,14 +134,19 @@ namespace OpenSim.Framework.Monitoring
120 } 134 }
121 135
122 private static void OutputCategoryStatsToConsole( 136 private static void OutputCategoryStatsToConsole(
123 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category) 137 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
124 { 138 {
125 foreach (var container in category.Values) 139 foreach (var container in category.Values)
126 { 140 {
127 foreach (Stat stat in container.Values) 141 OutputContainerStatsToConsole(con, container);
128 { 142 }
129 con.Output(stat.ToConsoleString()); 143 }
130 } 144
145 private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary<string, Stat> container)
146 {
147 foreach (Stat stat in container.Values)
148 {
149 con.Output(stat.ToConsoleString());
131 } 150 }
132 } 151 }
133 152
@@ -160,8 +179,8 @@ namespace OpenSim.Framework.Monitoring
160 /// <returns></returns> 179 /// <returns></returns>
161 public static bool RegisterStat(Stat stat) 180 public static bool RegisterStat(Stat stat)
162 { 181 {
163 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory; 182 SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
164 Dictionary<string, Stat> container = null, newContainer; 183 SortedDictionary<string, Stat> container = null, newContainer;
165 184
166 lock (RegisteredStats) 185 lock (RegisteredStats)
167 { 186 {
@@ -175,14 +194,14 @@ namespace OpenSim.Framework.Monitoring
175 // This means that we don't need to lock or copy them on iteration, which will be a much more 194 // This means that we don't need to lock or copy them on iteration, which will be a much more
176 // common operation after startup. 195 // common operation after startup.
177 if (container != null) 196 if (container != null)
178 newContainer = new Dictionary<string, Stat>(container); 197 newContainer = new SortedDictionary<string, Stat>(container);
179 else 198 else
180 newContainer = new Dictionary<string, Stat>(); 199 newContainer = new SortedDictionary<string, Stat>();
181 200
182 if (category != null) 201 if (category != null)
183 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 202 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
184 else 203 else
185 newCategory = new Dictionary<string, Dictionary<string, Stat>>(); 204 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>();
186 205
187 newContainer[stat.ShortName] = stat; 206 newContainer[stat.ShortName] = stat;
188 newCategory[stat.Container] = newContainer; 207 newCategory[stat.Container] = newContainer;
@@ -196,21 +215,21 @@ namespace OpenSim.Framework.Monitoring
196 /// Deregister a statistic 215 /// Deregister a statistic
197 /// </summary>> 216 /// </summary>>
198 /// <param name='stat'></param> 217 /// <param name='stat'></param>
199 /// <returns></returns 218 /// <returns></returns>
200 public static bool DeregisterStat(Stat stat) 219 public static bool DeregisterStat(Stat stat)
201 { 220 {
202 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory; 221 SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
203 Dictionary<string, Stat> container = null, newContainer; 222 SortedDictionary<string, Stat> container = null, newContainer;
204 223
205 lock (RegisteredStats) 224 lock (RegisteredStats)
206 { 225 {
207 if (!TryGetStat(stat, out category, out container)) 226 if (!TryGetStat(stat, out category, out container))
208 return false; 227 return false;
209 228
210 newContainer = new Dictionary<string, Stat>(container); 229 newContainer = new SortedDictionary<string, Stat>(container);
211 newContainer.Remove(stat.ShortName); 230 newContainer.Remove(stat.ShortName);
212 231
213 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 232 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
214 newCategory.Remove(stat.Container); 233 newCategory.Remove(stat.Container);
215 234
216 newCategory[stat.Container] = newContainer; 235 newCategory[stat.Container] = newContainer;
@@ -220,15 +239,15 @@ namespace OpenSim.Framework.Monitoring
220 } 239 }
221 } 240 }
222 241
223 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats) 242 public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
224 { 243 {
225 return RegisteredStats.TryGetValue(category, out stats); 244 return RegisteredStats.TryGetValue(category, out stats);
226 } 245 }
227 246
228 public static bool TryGetStat( 247 public static bool TryGetStat(
229 Stat stat, 248 Stat stat,
230 out Dictionary<string, Dictionary<string, Stat>> category, 249 out SortedDictionary<string, SortedDictionary<string, Stat>> category,
231 out Dictionary<string, Stat> container) 250 out SortedDictionary<string, Stat> container)
232 { 251 {
233 category = null; 252 category = null;
234 container = null; 253 container = null;
@@ -252,9 +271,9 @@ namespace OpenSim.Framework.Monitoring
252 { 271 {
253 lock (RegisteredStats) 272 lock (RegisteredStats)
254 { 273 {
255 foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values) 274 foreach (SortedDictionary<string, SortedDictionary<string, Stat>> category in RegisteredStats.Values)
256 { 275 {
257 foreach (Dictionary<string, Stat> container in category.Values) 276 foreach (SortedDictionary<string, Stat> container in category.Values)
258 { 277 {
259 foreach (Stat stat in container.Values) 278 foreach (Stat stat in container.Values)
260 { 279 {
diff --git a/OpenSim/Framework/Monitoring/UserStatsCollector.cs b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
index e89c8e6..81e0fa4 100644
--- a/OpenSim/Framework/Monitoring/UserStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
@@ -27,6 +27,8 @@
27 27
28using System.Timers; 28using System.Timers;
29 29
30using OpenMetaverse.StructuredData;
31
30namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
31{ 33{
32 /// <summary> 34 /// <summary>
@@ -88,5 +90,21 @@ namespace OpenSim.Framework.Monitoring
88 Logouts total : {3}", 90 Logouts total : {3}",
89 SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts); 91 SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts);
90 } 92 }
93
94 public override string XReport(string uptime, string version)
95 {
96 return OSDParser.SerializeJsonString(OReport(uptime, version));
97 }
98
99 public override OSDMap OReport(string uptime, string version)
100 {
101 OSDMap ret = new OSDMap();
102 ret.Add("SuccessfulLogins", OSD.FromInteger(SuccessfulLogins));
103 ret.Add("SuccessfulLoginsToday", OSD.FromInteger(SuccessfulLoginsToday));
104 ret.Add("SuccessfulLoginsYesterday", OSD.FromInteger(SuccessfulLoginsYesterday));
105 ret.Add("Logouts", OSD.FromInteger(Logouts));
106
107 return ret;
108 }
91 } 109 }
92} 110}
diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs
new file mode 100644
index 0000000..0117096
--- /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
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)
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..df928dc 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)
@@ -631,6 +622,8 @@ namespace OpenSim.Framework
631 } 622 }
632 } 623 }
633 624
625 // This is only used at runtime. For sculpties this holds the texture data, and for meshes
626 // the mesh data.
634 public byte[] SculptData 627 public byte[] SculptData
635 { 628 {
636 get 629 get
@@ -1184,14 +1177,13 @@ namespace OpenSim.Framework
1184 1177
1185 public void ReadSculptData(byte[] data, int pos) 1178 public void ReadSculptData(byte[] data, int pos)
1186 { 1179 {
1187 byte[] SculptTextureUUID = new byte[16]; 1180 UUID SculptUUID;
1188 UUID SculptUUID = UUID.Zero; 1181 byte SculptTypel;
1189 byte SculptTypel = data[16+pos];
1190 1182
1191 if (data.Length+pos >= 17) 1183 if (data.Length-pos >= 17)
1192 { 1184 {
1193 _sculptEntry = true; 1185 _sculptEntry = true;
1194 SculptTextureUUID = new byte[16]; 1186 byte[] SculptTextureUUID = new byte[16];
1195 SculptTypel = data[16 + pos]; 1187 SculptTypel = data[16 + pos];
1196 Array.Copy(data, pos, SculptTextureUUID,0, 16); 1188 Array.Copy(data, pos, SculptTextureUUID,0, 16);
1197 SculptUUID = new UUID(SculptTextureUUID, 0); 1189 SculptUUID = new UUID(SculptTextureUUID, 0);
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index e7bed6a..6dde62f 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -145,6 +145,7 @@ namespace OpenSim.Framework
145 public UUID RegionID = UUID.Zero; 145 public UUID RegionID = UUID.Zero;
146 public string RemotingAddress; 146 public string RemotingAddress;
147 public UUID ScopeID = UUID.Zero; 147 public UUID ScopeID = UUID.Zero;
148 private UUID m_maptileStaticUUID = UUID.Zero;
148 149
149 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); 150 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>();
150 151
@@ -340,6 +341,11 @@ namespace OpenSim.Framework
340 get { return m_regionType; } 341 get { return m_regionType; }
341 } 342 }
342 343
344 public UUID MaptileStaticUUID
345 {
346 get { return m_maptileStaticUUID; }
347 }
348
343 /// <summary> 349 /// <summary>
344 /// The port by which http communication occurs with the region (most noticeably, CAPS communication) 350 /// The port by which http communication occurs with the region (most noticeably, CAPS communication)
345 /// </summary> 351 /// </summary>
@@ -643,7 +649,7 @@ namespace OpenSim.Framework
643 m_regionType = config.GetString("RegionType", String.Empty); 649 m_regionType = config.GetString("RegionType", String.Empty);
644 allKeys.Remove("RegionType"); 650 allKeys.Remove("RegionType");
645 651
646 #region Prim stuff 652 #region Prim and map stuff
647 653
648 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0); 654 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
649 allKeys.Remove("NonPhysicalPrimMin"); 655 allKeys.Remove("NonPhysicalPrimMin");
@@ -665,6 +671,13 @@ namespace OpenSim.Framework
665 671
666 m_linksetCapacity = config.GetInt("LinksetPrims", 0); 672 m_linksetCapacity = config.GetInt("LinksetPrims", 0);
667 allKeys.Remove("LinksetPrims"); 673 allKeys.Remove("LinksetPrims");
674
675 allKeys.Remove("MaptileStaticUUID");
676 string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString());
677 if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID))
678 {
679 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
680 }
668 681
669 #endregion 682 #endregion
670 683
@@ -734,6 +747,9 @@ namespace OpenSim.Framework
734 747
735 if (RegionType != String.Empty) 748 if (RegionType != String.Empty)
736 config.Set("RegionType", RegionType); 749 config.Set("RegionType", RegionType);
750
751 if (m_maptileStaticUUID != UUID.Zero)
752 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
737 } 753 }
738 754
739 public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result) 755 public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result)
@@ -832,6 +848,9 @@ namespace OpenSim.Framework
832 848
833 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, 849 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
834 "Free form string describing the type of region", String.Empty, true); 850 "Free form string describing the type of region", String.Empty, true);
851
852 configMember.addConfigurationOption("region_static_maptile", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
853 "UUID of a texture to use as the map for this region", m_maptileStaticUUID.ToString(), true);
835 } 854 }
836 855
837 public void loadConfigurationOptions() 856 public void loadConfigurationOptions()
@@ -885,6 +904,9 @@ namespace OpenSim.Framework
885 904
886 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, 905 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
887 "Region Type", String.Empty, true); 906 "Region Type", String.Empty, true);
907
908 configMember.addConfigurationOption("region_static_maptile", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
909 "UUID of a texture to use as the map for this region", String.Empty, true);
888 } 910 }
889 911
890 public bool handleIncomingConfiguration(string configuration_key, object configuration_result) 912 public bool handleIncomingConfiguration(string configuration_key, object configuration_result)
@@ -957,6 +979,9 @@ namespace OpenSim.Framework
957 case "region_type": 979 case "region_type":
958 m_regionType = (string)configuration_result; 980 m_regionType = (string)configuration_result;
959 break; 981 break;
982 case "region_static_maptile":
983 m_maptileStaticUUID = (UUID)configuration_result;
984 break;
960 } 985 }
961 986
962 return true; 987 return true;
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
index d670f2f..d4806f1 100644
--- a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
index 7309a12..1541a5b 100644
--- a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
index 11efa4b..a8dff93 100644
--- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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..6c04c69 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
@@ -309,4 +189,4 @@ namespace OpenSim.Framework.Servers
309 } 189 }
310 } 190 }
311 } 191 }
312} \ No newline at end of file 192}
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 77fce9e..97035e3 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -54,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); 55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
56 56
57
58 /// <summary>
59 /// This is a pending websocket request before it got an sucessful upgrade response.
60 /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
61 /// start the connection and optionally provide an origin authentication method.
62 /// </summary>
63 /// <param name="servicepath"></param>
64 /// <param name="handler"></param>
65 public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler);
66
57 /// <summary> 67 /// <summary>
58 /// Gets or sets the debug level. 68 /// Gets or sets the debug level.
59 /// </summary> 69 /// </summary>
@@ -77,6 +87,7 @@ namespace OpenSim.Framework.Servers.HttpServer
77 // protected HttpListener m_httpListener; 87 // protected HttpListener m_httpListener;
78 protected CoolHTTPListener m_httpListener2; 88 protected CoolHTTPListener m_httpListener2;
79 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); 89 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
90 protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
80 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); 91 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/ 92 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>(); 93 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
@@ -86,6 +97,9 @@ namespace OpenSim.Framework.Servers.HttpServer
86 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = 97 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
87 new Dictionary<string, PollServiceEventArgs>(); 98 new Dictionary<string, PollServiceEventArgs>();
88 99
100 protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
101 new Dictionary<string, WebSocketRequestDelegate>();
102
89 protected uint m_port; 103 protected uint m_port;
90 protected uint m_sslport; 104 protected uint m_sslport;
91 protected bool m_ssl; 105 protected bool m_ssl;
@@ -169,6 +183,22 @@ namespace OpenSim.Framework.Servers.HttpServer
169 } 183 }
170 } 184 }
171 185
186 public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
187 {
188 lock (m_WebSocketHandlers)
189 {
190 if (!m_WebSocketHandlers.ContainsKey(servicepath))
191 m_WebSocketHandlers.Add(servicepath, handler);
192 }
193 }
194
195 public void RemoveWebSocketHandler(string servicepath)
196 {
197 lock (m_WebSocketHandlers)
198 if (m_WebSocketHandlers.ContainsKey(servicepath))
199 m_WebSocketHandlers.Remove(servicepath);
200 }
201
172 public List<string> GetStreamHandlerKeys() 202 public List<string> GetStreamHandlerKeys()
173 { 203 {
174 lock (m_streamHandlers) 204 lock (m_streamHandlers)
@@ -217,6 +247,37 @@ namespace OpenSim.Framework.Servers.HttpServer
217 return new List<string>(m_rpcHandlers.Keys); 247 return new List<string>(m_rpcHandlers.Keys);
218 } 248 }
219 249
250 // JsonRPC
251 public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
252 {
253 lock(jsonRpcHandlers)
254 {
255 jsonRpcHandlers.Add(method, handler);
256 }
257 return true;
258 }
259
260 public JsonRPCMethod GetJsonRPCHandler(string method)
261 {
262 lock (jsonRpcHandlers)
263 {
264 if (jsonRpcHandlers.ContainsKey(method))
265 {
266 return jsonRpcHandlers[method];
267 }
268 else
269 {
270 return null;
271 }
272 }
273 }
274
275 public List<string> GetJsonRpcHandlerKeys()
276 {
277 lock (jsonRpcHandlers)
278 return new List<string>(jsonRpcHandlers.Keys);
279 }
280
220 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) 281 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
221 { 282 {
222 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); 283 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
@@ -378,9 +439,24 @@ namespace OpenSim.Framework.Servers.HttpServer
378 439
379 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) 440 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
380 { 441 {
442
381 OSHttpRequest req = new OSHttpRequest(context, request); 443 OSHttpRequest req = new OSHttpRequest(context, request);
444 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
445 lock (m_WebSocketHandlers)
446 {
447 if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
448 dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
449 }
450 if (dWebSocketRequestDelegate != null)
451 {
452 dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
453 return;
454 }
455
382 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 456 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
457
383 HandleRequest(req, resp); 458 HandleRequest(req, resp);
459
384 460
385 // !!!HACK ALERT!!! 461 // !!!HACK ALERT!!!
386 // There seems to be a bug in the underlying http code that makes subsequent requests 462 // There seems to be a bug in the underlying http code that makes subsequent requests
@@ -411,7 +487,9 @@ namespace OpenSim.Framework.Servers.HttpServer
411 { 487 {
412 try 488 try
413 { 489 {
414 SendHTML500(response); 490 byte[] buffer500 = SendHTML500(response);
491 response.Body.Write(buffer500,0,buffer500.Length);
492 response.Body.Close();
415 } 493 }
416 catch 494 catch
417 { 495 {
@@ -437,7 +515,7 @@ namespace OpenSim.Framework.Servers.HttpServer
437// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); 515// 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); 516 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
439 517
440 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 518 Culture.SetCurrentCulture();
441 519
442// // This is the REST agent interface. We require an agent to properly identify 520// // 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 521// // itself. If the REST handler recognizes the prefix it will attempt to
@@ -469,7 +547,7 @@ namespace OpenSim.Framework.Servers.HttpServer
469 LogIncomingToStreamHandler(request, requestHandler); 547 LogIncomingToStreamHandler(request, requestHandler);
470 548
471 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. 549 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
472 550
473 if (requestHandler is IStreamedRequestHandler) 551 if (requestHandler is IStreamedRequestHandler)
474 { 552 {
475 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; 553 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
@@ -557,10 +635,18 @@ namespace OpenSim.Framework.Servers.HttpServer
557 635
558 buffer = HandleLLSDRequests(request, response); 636 buffer = HandleLLSDRequests(request, response);
559 break; 637 break;
638
639 case "application/json-rpc":
640 if (DebugLevel >= 3)
641 LogIncomingToContentTypeHandler(request);
642
643 buffer = HandleJsonRpcRequests(request, response);
644 break;
560 645
561 case "text/xml": 646 case "text/xml":
562 case "application/xml": 647 case "application/xml":
563 case "application/json": 648 case "application/json":
649
564 default: 650 default:
565 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); 651 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
566 // Point of note.. the DoWeHaveA methods check for an EXACT path 652 // Point of note.. the DoWeHaveA methods check for an EXACT path
@@ -636,7 +722,15 @@ namespace OpenSim.Framework.Servers.HttpServer
636 catch (Exception e) 722 catch (Exception e)
637 { 723 {
638 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); 724 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
639 SendHTML500(response); 725 try
726 {
727 byte[] buffer500 = SendHTML500(response);
728 response.Body.Write(buffer500, 0, buffer500.Length);
729 response.Body.Close();
730 }
731 catch
732 {
733 }
640 } 734 }
641 finally 735 finally
642 { 736 {
@@ -986,6 +1080,93 @@ namespace OpenSim.Framework.Servers.HttpServer
986 return buffer; 1080 return buffer;
987 } 1081 }
988 1082
1083 // JsonRpc (v2.0 only)
1084 // Batch requests not yet supported
1085 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1086 {
1087 Stream requestStream = request.InputStream;
1088 JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
1089 OSDMap jsonRpcRequest = null;
1090
1091 try
1092 {
1093 jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
1094 }
1095 catch (LitJson.JsonException e)
1096 {
1097 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1098 jsonRpcResponse.Error.Message = e.Message;
1099 }
1100
1101 requestStream.Close();
1102
1103 if (jsonRpcRequest != null)
1104 {
1105 if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
1106 {
1107 jsonRpcResponse.JsonRpc = "2.0";
1108
1109 // If we have no id, then it's a "notification"
1110 if (jsonRpcRequest.ContainsKey("id"))
1111 {
1112 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1113 }
1114
1115 string methodname = jsonRpcRequest["method"];
1116 JsonRPCMethod method;
1117
1118 if (jsonRpcHandlers.ContainsKey(methodname))
1119 {
1120 lock(jsonRpcHandlers)
1121 {
1122 jsonRpcHandlers.TryGetValue(methodname, out method);
1123 }
1124 bool res = false;
1125 try
1126 {
1127 res = method(jsonRpcRequest, ref jsonRpcResponse);
1128 if(!res)
1129 {
1130 // The handler sent back an unspecified error
1131 if(jsonRpcResponse.Error.Code == 0)
1132 {
1133 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1134 }
1135 }
1136 }
1137 catch (Exception e)
1138 {
1139 string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1140 m_log.Error(ErrorMessage);
1141 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1142 jsonRpcResponse.Error.Message = ErrorMessage;
1143 }
1144 }
1145 else // Error no hanlder defined for requested method
1146 {
1147 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1148 jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
1149 }
1150 }
1151 else // not json-rpc 2.0 could be v1
1152 {
1153 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1154 jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1155
1156 if (jsonRpcRequest.ContainsKey("id"))
1157 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1158 }
1159 }
1160
1161 response.KeepAlive = true;
1162 string responseData = string.Empty;
1163
1164 responseData = jsonRpcResponse.Serialize();
1165
1166 byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1167 return buffer;
1168 }
1169
989 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) 1170 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
990 { 1171 {
991 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); 1172 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
@@ -1283,59 +1464,6 @@ namespace OpenSim.Framework.Servers.HttpServer
1283 map["login"] = OSD.FromString("false"); 1464 map["login"] = OSD.FromString("false");
1284 return map; 1465 return map;
1285 } 1466 }
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 1467
1340 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) 1468 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
1341 { 1469 {
@@ -1674,7 +1802,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1674 response.SendChunked = false; 1802 response.SendChunked = false;
1675 response.ContentLength64 = buffer.Length; 1803 response.ContentLength64 = buffer.Length;
1676 response.ContentEncoding = Encoding.UTF8; 1804 response.ContentEncoding = Encoding.UTF8;
1677 1805
1806
1678 return buffer; 1807 return buffer;
1679 } 1808 }
1680 1809
@@ -1775,6 +1904,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1775 HTTPDRunning = false; 1904 HTTPDRunning = false;
1776 try 1905 try
1777 { 1906 {
1907// m_PollServiceManager.Stop();
1908
1778 m_httpListener2.ExceptionThrown -= httpServerException; 1909 m_httpListener2.ExceptionThrown -= httpServerException;
1779 //m_httpListener2.DisconnectHandler = null; 1910 //m_httpListener2.DisconnectHandler = null;
1780 1911
@@ -1840,6 +1971,12 @@ namespace OpenSim.Framework.Servers.HttpServer
1840 m_rpcHandlers.Remove(method); 1971 m_rpcHandlers.Remove(method);
1841 } 1972 }
1842 1973
1974 public void RemoveJsonRPCHandler(string method)
1975 {
1976 lock(jsonRpcHandlers)
1977 jsonRpcHandlers.Remove(method);
1978 }
1979
1843 public bool RemoveLLSDHandler(string path, LLSDMethod handler) 1980 public bool RemoveLLSDHandler(string path, LLSDMethod handler)
1844 { 1981 {
1845 lock (m_llsdHandlers) 1982 lock (m_llsdHandlers)
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index 0bd3aae..d162bc1 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -97,6 +97,18 @@ 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
102 /// <summary>
103 /// Websocket HTTP server handlers.
104 /// </summary>
105 /// <param name="servicepath"></param>
106 /// <param name="handler"></param>
107 void AddWebSocketHandler(string servicepath, BaseHttpServer.WebSocketRequestDelegate handler);
108
109
110 void RemoveWebSocketHandler(string servicepath);
111
100 /// <summary> 112 /// <summary>
101 /// Gets the XML RPC handler for given method name 113 /// Gets the XML RPC handler for given method name
102 /// </summary> 114 /// </summary>
@@ -128,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer
128 void RemoveStreamHandler(string httpMethod, string path); 140 void RemoveStreamHandler(string httpMethod, string path);
129 141
130 void RemoveXmlRPCHandler(string method); 142 void RemoveXmlRPCHandler(string method);
143
144 void RemoveJsonRPCHandler(string method);
131 145
132 string GetHTTP404(string host); 146 string GetHTTP404(string host);
133 147
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
index 812a21c..5bab508 100644
--- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -25,14 +25,10 @@
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
28//TODO: WHERE TO PLACE THIS? 28using System.Net;
29using OpenMetaverse.StructuredData;
29 30
30namespace OpenSim.Region.Framework.Scenes.Scripting 31namespace OpenSim.Framework.Servers.HttpServer
31{ 32{
32 public interface ScriptEngineInterface 33 public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
33 {
34 void InitializeEngine(Scene Sceneworld);
35 void Shutdown();
36// void StartScript(string ScriptID, IScriptHost ObjectID);
37 }
38} 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/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 4be8bf4..7628e23 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -50,19 +50,26 @@ namespace OpenSim.Framework.Servers.HttpServer
50 private uint m_WorkerThreadCount = 0; 50 private uint m_WorkerThreadCount = 0;
51 private Thread[] m_workerThreads; 51 private Thread[] m_workerThreads;
52 private PollServiceWorkerThread[] m_PollServiceWorkerThreads; 52 private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
53 private bool m_running = true; 53 private volatile bool m_running = true;
54 private int m_pollTimeout;
54 55
55 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 56 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
56 { 57 {
57 m_server = pSrv; 58 m_server = pSrv;
58 m_WorkerThreadCount = pWorkerThreadCount; 59 m_WorkerThreadCount = pWorkerThreadCount;
60 m_pollTimeout = pTimeout;
61 }
62
63 public void Start()
64 {
65 m_running = true;
59 m_workerThreads = new Thread[m_WorkerThreadCount]; 66 m_workerThreads = new Thread[m_WorkerThreadCount];
60 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; 67 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
61 68
62 //startup worker threads 69 //startup worker threads
63 for (uint i = 0; i < m_WorkerThreadCount; i++) 70 for (uint i = 0; i < m_WorkerThreadCount; i++)
64 { 71 {
65 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout); 72 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
66 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; 73 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
67 74
68 m_workerThreads[i] 75 m_workerThreads[i]
@@ -141,8 +148,10 @@ namespace OpenSim.Framework.Servers.HttpServer
141 148
142 } 149 }
143 150
144 ~PollServiceRequestManager() 151 public void Stop()
145 { 152 {
153 m_running = false;
154
146 foreach (object o in m_requests) 155 foreach (object o in m_requests)
147 { 156 {
148 PollServiceHttpRequest req = (PollServiceHttpRequest) o; 157 PollServiceHttpRequest req = (PollServiceHttpRequest) o;
@@ -157,7 +166,6 @@ namespace OpenSim.Framework.Servers.HttpServer
157 { 166 {
158 t.Abort(); 167 t.Abort();
159 } 168 }
160 m_running = false;
161 } 169 }
162 } 170 }
163} 171}
@@ -337,7 +345,7 @@ namespace OpenSim.Framework.Servers.HttpServer
337 if (responsedata == null) 345 if (responsedata == null)
338 continue; 346 continue;
339 347
340 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) 348 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue
341 { 349 {
342 try 350 try
343 { 351 {
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
index 02ecc25..8e592c1 100644
--- a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
index 19c03a8..edcd134 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
@@ -101,20 +101,11 @@ namespace OpenSim.Framework.Servers.HttpServer
101 using (WebResponse resp = request.GetResponse()) 101 using (WebResponse resp = request.GetResponse())
102 { 102 {
103 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); 103 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
104 Stream respStream = null; 104
105 try 105 using (Stream respStream = resp.GetResponseStream())
106 {
107 respStream = resp.GetResponseStream();
108 deserial = (TResponse)deserializer.Deserialize(respStream); 106 deserial = (TResponse)deserializer.Deserialize(respStream);
109 }
110 catch { }
111 finally
112 {
113 if (respStream != null)
114 respStream.Close();
115 resp.Close();
116 }
117 } 107 }
108
118 return deserial; 109 return deserial;
119 } 110 }
120 } 111 }
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
new file mode 100644
index 0000000..ee96b47
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -0,0 +1,1102 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Security.Cryptography;
32using System.Text;
33using HttpServer;
34
35namespace OpenSim.Framework.Servers.HttpServer
36{
37 // Sealed class. If you're going to unseal it, implement IDisposable.
38 /// <summary>
39 /// This class implements websockets. It grabs the network context from C#Webserver and utilizes it directly as a tcp streaming service
40 /// </summary>
41 public sealed class WebSocketHttpServerHandler : BaseRequestHandler
42 {
43
44 private class WebSocketState
45 {
46 public List<byte> ReceivedBytes;
47 public int ExpectedBytes;
48 public WebsocketFrameHeader Header;
49 public bool FrameComplete;
50 public WebSocketFrame ContinuationFrame;
51 }
52
53 /// <summary>
54 /// Binary Data will trigger this event
55 /// </summary>
56 public event DataDelegate OnData;
57
58 /// <summary>
59 /// Textual Data will trigger this event
60 /// </summary>
61 public event TextDelegate OnText;
62
63 /// <summary>
64 /// A ping request form the other side will trigger this event.
65 /// This class responds to the ping automatically. You shouldn't send a pong.
66 /// it's informational.
67 /// </summary>
68 public event PingDelegate OnPing;
69
70 /// <summary>
71 /// This is a response to a ping you sent.
72 /// </summary>
73 public event PongDelegate OnPong;
74
75 /// <summary>
76 /// This is a regular HTTP Request... This may be removed in the future.
77 /// </summary>
78 public event RegularHttpRequestDelegate OnRegularHttpRequest;
79
80 /// <summary>
81 /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
82 /// </summary>
83 public event UpgradeCompletedDelegate OnUpgradeCompleted;
84
85 /// <summary>
86 /// If the upgrade failed, this will be fired
87 /// </summary>
88 public event UpgradeFailedDelegate OnUpgradeFailed;
89
90 /// <summary>
91 /// When the websocket is closed, this will be fired.
92 /// </summary>
93 public event CloseDelegate OnClose;
94
95 /// <summary>
96 /// Set this delegate to allow your module to validate the origin of the
97 /// Websocket request. Primary line of defense against cross site scripting
98 /// </summary>
99 public ValidateHandshake HandshakeValidateMethodOverride = null;
100
101 private OSHttpRequest _request;
102 private HTTPNetworkContext _networkContext;
103 private IHttpClientContext _clientContext;
104
105 private int _pingtime = 0;
106 private byte[] _buffer;
107 private int _bufferPosition;
108 private int _bufferLength;
109 private bool _closing;
110 private bool _upgraded;
111 private int _maxPayloadBytes = 41943040;
112
113 private const string HandshakeAcceptText =
114 "HTTP/1.1 101 Switching Protocols\r\n" +
115 "upgrade: websocket\r\n" +
116 "Connection: Upgrade\r\n" +
117 "sec-websocket-accept: {0}\r\n\r\n";// +
118 //"{1}";
119
120 private const string HandshakeDeclineText =
121 "HTTP/1.1 {0} {1}\r\n" +
122 "Connection: close\r\n\r\n";
123
124 /// <summary>
125 /// Mysterious constant defined in RFC6455 to append to the client provided security key
126 /// </summary>
127 private const string WebsocketHandshakeAcceptHashConstant = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
128
129 public WebSocketHttpServerHandler(OSHttpRequest preq, IHttpClientContext pContext, int bufferlen)
130 : base(preq.HttpMethod, preq.Url.OriginalString)
131 {
132 _request = preq;
133 _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing();
134 _clientContext = pContext;
135 _bufferLength = bufferlen;
136 _buffer = new byte[_bufferLength];
137 }
138
139 // Sealed class implments destructor and an internal dispose method. complies with C# unmanaged resource best practices.
140 ~WebSocketHttpServerHandler()
141 {
142 Dispose();
143
144 }
145
146 /// <summary>
147 /// Sets the length of the stream buffer
148 /// </summary>
149 /// <param name="pChunk">Byte length.</param>
150 public void SetChunksize(int pChunk)
151 {
152 if (!_upgraded)
153 {
154 _buffer = new byte[pChunk];
155 }
156 else
157 {
158 throw new InvalidOperationException("You must set the chunksize before the connection is upgraded");
159 }
160 }
161
162 /// <summary>
163 /// This is the famous nagle.
164 /// </summary>
165 public bool NoDelay_TCP_Nagle
166 {
167 get
168 {
169 if (_networkContext != null && _networkContext.Socket != null)
170 {
171 return _networkContext.Socket.NoDelay;
172 }
173 else
174 {
175 throw new InvalidOperationException("The socket has been shutdown");
176 }
177 }
178 set
179 {
180 if (_networkContext != null && _networkContext.Socket != null)
181 _networkContext.Socket.NoDelay = value;
182 else
183 {
184 throw new InvalidOperationException("The socket has been shutdown");
185 }
186 }
187 }
188
189 /// <summary>
190 /// This triggers the websocket to start the upgrade process...
191 /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead
192 /// of the more context appropriate HandshakeAndUpgrade()
193 /// </summary>
194 public void Start()
195 {
196 HandshakeAndUpgrade();
197 }
198
199 /// <summary>
200 /// Max Payload Size in bytes. Defaults to 40MB, but could be set upon connection before calling handshake and upgrade.
201 /// </summary>
202 public int MaxPayloadSize
203 {
204 get { return _maxPayloadBytes; }
205 set { _maxPayloadBytes = value; }
206 }
207
208 /// <summary>
209 /// This triggers the websocket start the upgrade process
210 /// </summary>
211 public void HandshakeAndUpgrade()
212 {
213 string webOrigin = string.Empty;
214 string websocketKey = string.Empty;
215 string acceptKey = string.Empty;
216 string accepthost = string.Empty;
217 if (!string.IsNullOrEmpty(_request.Headers["origin"]))
218 webOrigin = _request.Headers["origin"];
219
220 if (!string.IsNullOrEmpty(_request.Headers["sec-websocket-key"]))
221 websocketKey = _request.Headers["sec-websocket-key"];
222
223 if (!string.IsNullOrEmpty(_request.Headers["host"]))
224 accepthost = _request.Headers["host"];
225
226 if (string.IsNullOrEmpty(_request.Headers["upgrade"]))
227 {
228 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no upgrade request submitted");
229 }
230
231 string connectionheader = _request.Headers["upgrade"];
232 if (connectionheader.ToLower() != "websocket")
233 {
234 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no connection upgrade request submitted");
235 }
236
237 // If the object consumer provided a method to validate the origin, we should call it and give the client a success or fail.
238 // If not.. we should accept any. The assumption here is that there would be no Websocket handlers registered in baseHTTPServer unless
239 // Something asked for it...
240 if (HandshakeValidateMethodOverride != null)
241 {
242 if (HandshakeValidateMethodOverride(webOrigin, websocketKey, accepthost))
243 {
244 acceptKey = GenerateAcceptKey(websocketKey);
245 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
246 SendUpgradeSuccess(rawaccept);
247
248 }
249 else
250 {
251 FailUpgrade(OSHttpStatusCode.ClientErrorForbidden, "Origin Validation Failed");
252 }
253 }
254 else
255 {
256 acceptKey = GenerateAcceptKey(websocketKey);
257 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
258 SendUpgradeSuccess(rawaccept);
259 }
260 }
261
262 /// <summary>
263 /// Generates a handshake response key string based on the client's
264 /// provided key to prove to the client that we're allowing the Websocket
265 /// upgrade of our own free will and we were not coerced into doing it.
266 /// </summary>
267 /// <param name="key">Client provided security key</param>
268 /// <returns></returns>
269 private static string GenerateAcceptKey(string key)
270 {
271 if (string.IsNullOrEmpty(key))
272 return string.Empty;
273
274 string acceptkey = key + WebsocketHandshakeAcceptHashConstant;
275
276 SHA1 hashobj = SHA1.Create();
277 string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey)));
278 hashobj.Clear();
279
280 return ret;
281 }
282
283 /// <summary>
284 /// Informs the otherside that we accepted their upgrade request
285 /// </summary>
286 /// <param name="pHandshakeResponse">The HTTP 1.1 101 response that says Yay \o/ </param>
287 private void SendUpgradeSuccess(string pHandshakeResponse)
288 {
289 // Create a new websocket state so we can keep track of data in between network reads.
290 WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true};
291
292 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);
293 try
294 {
295
296 // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
297 _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);
298
299 // Write the upgrade handshake success message
300 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
301 _networkContext.Stream.Flush();
302 _upgraded = true;
303 UpgradeCompletedDelegate d = OnUpgradeCompleted;
304 if (d != null)
305 d(this, new UpgradeCompletedEventArgs());
306 }
307 catch (IOException fail)
308 {
309 Close(string.Empty);
310 }
311 catch (ObjectDisposedException fail)
312 {
313 Close(string.Empty);
314 }
315
316 }
317
318 /// <summary>
319 /// The server has decided not to allow the upgrade to a websocket for some reason. The Http 1.1 response that says Nay >:(
320 /// </summary>
321 /// <param name="pCode">HTTP Status reflecting the reason why</param>
322 /// <param name="pMessage">Textual reason for the upgrade fail</param>
323 private void FailUpgrade(OSHttpStatusCode pCode, string pMessage )
324 {
325 string handshakeResponse = string.Format(HandshakeDeclineText, (int)pCode, pMessage.Replace("\n", string.Empty).Replace("\r", string.Empty));
326 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(handshakeResponse);
327 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
328 _networkContext.Stream.Flush();
329 _networkContext.Stream.Dispose();
330
331 UpgradeFailedDelegate d = OnUpgradeFailed;
332 if (d != null)
333 d(this,new UpgradeFailedEventArgs());
334 }
335
336
337 /// <summary>
338 /// This is our ugly Async OnReceive event handler.
339 /// This chunks the input stream based on the length of the provided buffer and processes out
340 /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer.
341 /// </summary>
342 /// <param name="ar">Our Async State from beginread</param>
343 private void OnReceive(IAsyncResult ar)
344 {
345 WebSocketState _socketState = ar.AsyncState as WebSocketState;
346 try
347 {
348 int bytesRead = _networkContext.Stream.EndRead(ar);
349 if (bytesRead == 0)
350 {
351 // Do Disconnect
352 _networkContext.Stream.Dispose();
353 _networkContext = null;
354 return;
355 }
356 _bufferPosition += bytesRead;
357
358 if (_bufferPosition > _bufferLength)
359 {
360 // Message too big for chunksize.. not sure how this happened...
361 //Close(string.Empty);
362 }
363
364 int offset = 0;
365 bool headerread = true;
366 int headerforwardposition = 0;
367 while (headerread && offset < bytesRead)
368 {
369 if (_socketState.FrameComplete)
370 {
371 WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader;
372
373 headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader,
374 out headerforwardposition);
375 offset += headerforwardposition;
376
377 if (headerread)
378 {
379 _socketState.FrameComplete = false;
380 if (pheader.PayloadLen > (ulong) _maxPayloadBytes)
381 {
382 Close("Invalid Payload size");
383
384 return;
385 }
386 if (pheader.PayloadLen > 0)
387 {
388 if ((int) pheader.PayloadLen > _bufferPosition - offset)
389 {
390 byte[] writebytes = new byte[_bufferPosition - offset];
391
392 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition - offset);
393 _socketState.ExpectedBytes = (int) pheader.PayloadLen;
394 _socketState.ReceivedBytes.AddRange(writebytes);
395 _socketState.Header = pheader; // We need to add the header so that we can unmask it
396 offset += (int) _bufferPosition - offset;
397 }
398 else
399 {
400 byte[] writebytes = new byte[pheader.PayloadLen];
401 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) pheader.PayloadLen);
402 WebSocketReader.Mask(pheader.Mask, writebytes);
403 pheader.IsMasked = false;
404 _socketState.FrameComplete = true;
405 _socketState.ReceivedBytes.AddRange(writebytes);
406 _socketState.Header = pheader;
407 offset += (int) pheader.PayloadLen;
408 }
409 }
410 else
411 {
412 pheader.Mask = 0;
413 _socketState.FrameComplete = true;
414 _socketState.Header = pheader;
415 }
416
417
418
419 if (_socketState.FrameComplete)
420 {
421 ProcessFrame(_socketState);
422 _socketState.Header.SetDefault();
423 _socketState.ReceivedBytes.Clear();
424 _socketState.ExpectedBytes = 0;
425
426 }
427
428 }
429 }
430 else
431 {
432 WebsocketFrameHeader frameHeader = _socketState.Header;
433 int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count;
434
435 if (bytesleft > _bufferPosition)
436 {
437 byte[] writebytes = new byte[_bufferPosition];
438
439 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
440 _socketState.ReceivedBytes.AddRange(writebytes);
441 _socketState.Header = frameHeader; // We need to add the header so that we can unmask it
442 offset += (int) _bufferPosition;
443 }
444 else
445 {
446 byte[] writebytes = new byte[_bufferPosition];
447 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
448 _socketState.FrameComplete = true;
449 _socketState.ReceivedBytes.AddRange(writebytes);
450 _socketState.Header = frameHeader;
451 offset += (int) _bufferPosition;
452 }
453 if (_socketState.FrameComplete)
454 {
455 ProcessFrame(_socketState);
456 _socketState.Header.SetDefault();
457 _socketState.ReceivedBytes.Clear();
458 _socketState.ExpectedBytes = 0;
459 // do some processing
460 }
461
462 }
463 }
464 if (offset > 0)
465 {
466 // If the buffer is maxed out.. we can just move the cursor. Nothing to move to the beginning.
467 if (offset <_buffer.Length)
468 Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset);
469 _bufferPosition -= offset;
470 }
471 if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing)
472 {
473 _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive,
474 _socketState);
475 }
476 else
477 {
478 // We can't read the stream anymore...
479 }
480
481 }
482 catch (IOException fail)
483 {
484 Close(string.Empty);
485 }
486 catch (ObjectDisposedException fail)
487 {
488 Close(string.Empty);
489 }
490 }
491
492 /// <summary>
493 /// Sends a string to the other side
494 /// </summary>
495 /// <param name="message">the string message that is to be sent</param>
496 public void SendMessage(string message)
497 {
498 byte[] messagedata = Encoding.UTF8.GetBytes(message);
499 WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata };
500 textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
501 textMessageFrame.Header.IsEnd = true;
502 SendSocket(textMessageFrame.ToBytes());
503
504 }
505
506 public void SendData(byte[] data)
507 {
508 WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data};
509 dataMessageFrame.Header.IsEnd = true;
510 dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
511 SendSocket(dataMessageFrame.ToBytes());
512
513 }
514
515 /// <summary>
516 /// Writes raw bytes to the websocket. Unframed data will cause disconnection
517 /// </summary>
518 /// <param name="data"></param>
519 private void SendSocket(byte[] data)
520 {
521 if (!_closing)
522 {
523 try
524 {
525
526 _networkContext.Stream.Write(data, 0, data.Length);
527 }
528 catch (IOException)
529 {
530
531 }
532 }
533 }
534
535 /// <summary>
536 /// Sends a Ping check to the other side. The other side SHOULD respond as soon as possible with a pong frame. This interleaves with incoming fragmented frames.
537 /// </summary>
538 public void SendPingCheck()
539 {
540 WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] };
541 pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
542 pingFrame.Header.IsEnd = true;
543 _pingtime = Util.EnvironmentTickCount();
544 SendSocket(pingFrame.ToBytes());
545 }
546
547 /// <summary>
548 /// Closes the websocket connection. Sends a close message to the other side if it hasn't already done so.
549 /// </summary>
550 /// <param name="message"></param>
551 public void Close(string message)
552 {
553 if (_networkContext == null)
554 return;
555 if (_networkContext.Stream != null)
556 {
557 if (_networkContext.Stream.CanWrite)
558 {
559 byte[] messagedata = Encoding.UTF8.GetBytes(message);
560 WebSocketFrame closeResponseFrame = new WebSocketFrame()
561 {
562 Header = WebsocketFrameHeader.HeaderDefault(),
563 WebSocketPayload = messagedata
564 };
565 closeResponseFrame.Header.Opcode = WebSocketReader.OpCode.Close;
566 closeResponseFrame.Header.PayloadLen = (ulong) messagedata.Length;
567 closeResponseFrame.Header.IsEnd = true;
568 SendSocket(closeResponseFrame.ToBytes());
569 }
570 }
571 CloseDelegate closeD = OnClose;
572 if (closeD != null)
573 {
574 closeD(this, new CloseEventArgs());
575 }
576
577 _closing = true;
578 }
579
580 /// <summary>
581 /// Processes a websocket frame and triggers consumer events
582 /// </summary>
583 /// <param name="psocketState">We need to modify the websocket state here depending on the frame</param>
584 private void ProcessFrame(WebSocketState psocketState)
585 {
586 if (psocketState.Header.IsMasked)
587 {
588 byte[] unmask = psocketState.ReceivedBytes.ToArray();
589 WebSocketReader.Mask(psocketState.Header.Mask, unmask);
590 psocketState.ReceivedBytes = new List<byte>(unmask);
591 }
592
593 switch (psocketState.Header.Opcode)
594 {
595 case WebSocketReader.OpCode.Ping:
596 PingDelegate pingD = OnPing;
597 if (pingD != null)
598 {
599 pingD(this, new PingEventArgs());
600 }
601
602 WebSocketFrame pongFrame = new WebSocketFrame(){Header = WebsocketFrameHeader.HeaderDefault(),WebSocketPayload = new byte[0]};
603 pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong;
604 pongFrame.Header.IsEnd = true;
605 SendSocket(pongFrame.ToBytes());
606 break;
607 case WebSocketReader.OpCode.Pong:
608
609 PongDelegate pongD = OnPong;
610 if (pongD != null)
611 {
612 pongD(this, new PongEventArgs(){PingResponseMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),_pingtime)});
613 }
614 break;
615 case WebSocketReader.OpCode.Binary:
616 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
617 {
618 psocketState.ContinuationFrame = new WebSocketFrame
619 {
620 Header = psocketState.Header,
621 WebSocketPayload =
622 psocketState.ReceivedBytes.ToArray()
623 };
624 }
625 else
626 {
627 // Send Done Event!
628 DataDelegate dataD = OnData;
629 if (dataD != null)
630 {
631 dataD(this,new WebsocketDataEventArgs(){Data = psocketState.ReceivedBytes.ToArray()});
632 }
633 }
634 break;
635 case WebSocketReader.OpCode.Text:
636 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
637 {
638 psocketState.ContinuationFrame = new WebSocketFrame
639 {
640 Header = psocketState.Header,
641 WebSocketPayload =
642 psocketState.ReceivedBytes.ToArray()
643 };
644 }
645 else
646 {
647 TextDelegate textD = OnText;
648 if (textD != null)
649 {
650 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) });
651 }
652
653 // Send Done Event!
654 }
655 break;
656 case WebSocketReader.OpCode.Continue: // Continuation. Multiple frames worth of data for one message. Only valid when not using Control Opcodes
657 //Console.WriteLine("currhead " + psocketState.Header.IsEnd);
658 //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd);
659 byte[] combineddata = new byte[psocketState.ReceivedBytes.Count+psocketState.ContinuationFrame.WebSocketPayload.Length];
660 byte[] newdata = psocketState.ReceivedBytes.ToArray();
661 Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length);
662 Buffer.BlockCopy(newdata, 0, combineddata,
663 psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length);
664 psocketState.ContinuationFrame.WebSocketPayload = combineddata;
665 psocketState.Header.PayloadLen = (ulong)combineddata.Length;
666 if (psocketState.Header.IsEnd)
667 {
668 if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text)
669 {
670 // Send Done event
671 TextDelegate textD = OnText;
672 if (textD != null)
673 {
674 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(combineddata) });
675 }
676 }
677 else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary)
678 {
679 // Send Done event
680 DataDelegate dataD = OnData;
681 if (dataD != null)
682 {
683 dataD(this, new WebsocketDataEventArgs() { Data = combineddata });
684 }
685 }
686 else
687 {
688 // protocol violation
689 }
690 psocketState.ContinuationFrame = null;
691 }
692 break;
693 case WebSocketReader.OpCode.Close:
694 Close(string.Empty);
695
696 break;
697
698 }
699 psocketState.Header.SetDefault();
700 psocketState.ReceivedBytes.Clear();
701 psocketState.ExpectedBytes = 0;
702 }
703 public void Dispose()
704 {
705 if (_networkContext != null && _networkContext.Stream != null)
706 {
707 if (_networkContext.Stream.CanWrite)
708 _networkContext.Stream.Flush();
709 _networkContext.Stream.Close();
710 _networkContext.Stream.Dispose();
711 _networkContext.Stream = null;
712 }
713
714 if (_request != null && _request.InputStream != null)
715 {
716 _request.InputStream.Close();
717 _request.InputStream.Dispose();
718 _request = null;
719 }
720
721 if (_clientContext != null)
722 {
723 _clientContext.Close();
724 _clientContext = null;
725 }
726 }
727 }
728
729 /// <summary>
730 /// Reads a byte stream and returns Websocket frames.
731 /// </summary>
732 public class WebSocketReader
733 {
734 /// <summary>
735 /// Bit to determine if the frame read on the stream is the last frame in a sequence of fragmented frames
736 /// </summary>
737 private const byte EndBit = 0x80;
738
739 /// <summary>
740 /// These are the Frame Opcodes
741 /// </summary>
742 public enum OpCode
743 {
744 // Data Opcodes
745 Continue = 0x0,
746 Text = 0x1,
747 Binary = 0x2,
748
749 // Control flow Opcodes
750 Close = 0x8,
751 Ping = 0x9,
752 Pong = 0xA
753 }
754
755 /// <summary>
756 /// Masks and Unmasks data using the frame mask. Mask is applied per octal
757 /// Note: Frames from clients MUST be masked
758 /// Note: Frames from servers MUST NOT be masked
759 /// </summary>
760 /// <param name="pMask">Int representing 32 bytes of mask data. Mask is applied per octal</param>
761 /// <param name="pBuffer"></param>
762 public static void Mask(int pMask, byte[] pBuffer)
763 {
764 byte[] maskKey = BitConverter.GetBytes(pMask);
765 int currentMaskIndex = 0;
766 for (int i = 0; i < pBuffer.Length; i++)
767 {
768 pBuffer[i] = (byte)(pBuffer[i] ^ maskKey[currentMaskIndex]);
769 if (currentMaskIndex == 3)
770 {
771 currentMaskIndex = 0;
772 }
773 else
774 {
775 currentMaskIndex++;
776
777 }
778
779 }
780 }
781
782 /// <summary>
783 /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader,
784 /// and an int to move the buffer forward when it reads a header. False when it can't read a header
785 /// </summary>
786 /// <param name="pBuffer">Bytes read from the stream</param>
787 /// <param name="pOffset">Starting place in the stream to begin trying to read from</param>
788 /// <param name="length">Lenth in the stream to try and read from. Provided for cases where the
789 /// buffer's length is larger then the data in it</param>
790 /// <param name="oHeader">Outputs the read WebSocket frame header</param>
791 /// <param name="moveBuffer">Informs the calling stream to move the buffer forward</param>
792 /// <returns>True if it got a header, False if it didn't get a header</returns>
793 public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader,
794 out int moveBuffer)
795 {
796 oHeader = WebsocketFrameHeader.ZeroHeader;
797 int minumheadersize = 2;
798 if (length > pBuffer.Length - pOffset)
799 throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied");
800 if (length < minumheadersize)
801 {
802 moveBuffer = 0;
803 return false;
804 }
805
806 byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3
807 byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block
808
809 oHeader = new WebsocketFrameHeader();
810 oHeader.SetDefault();
811
812 if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit)
813 {
814 oHeader.IsEnd = true;
815 }
816 else
817 {
818 oHeader.IsEnd = false;
819 }
820 //Opcode
821 oHeader.Opcode = (WebSocketReader.OpCode)nibble2;
822 //Mask
823 oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7);
824
825 // Payload length
826 oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F);
827
828 int index = 2; // LargerPayload length starts at byte 3
829
830 switch (oHeader.PayloadLen)
831 {
832 case 126:
833 minumheadersize += 2;
834 if (length < minumheadersize)
835 {
836 moveBuffer = 0;
837 return false;
838 }
839 Array.Reverse(pBuffer, pOffset + index, 2); // two bytes
840 oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index);
841 index += 2;
842 break;
843 case 127: // we got more this is a bigger frame
844 // 8 bytes - uint64 - most significant bit 0 network byte order
845 minumheadersize += 8;
846 if (length < minumheadersize)
847 {
848 moveBuffer = 0;
849 return false;
850 }
851 Array.Reverse(pBuffer, pOffset + index, 8);
852 oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index);
853 index += 8;
854 break;
855
856 }
857 //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation
858 if (oHeader.IsMasked)
859 {
860 minumheadersize += 4;
861 if (length < minumheadersize)
862 {
863 moveBuffer = 0;
864 return false;
865 }
866 oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index);
867 index += 4;
868 }
869 moveBuffer = index;
870 return true;
871
872 }
873 }
874
875 /// <summary>
876 /// RFC6455 Websocket Frame
877 /// </summary>
878 public class WebSocketFrame
879 {
880 /*
881 * RFC6455
882nib 0 1 2 3 4 5 6 7
883byt 0 1 2 3
884dec 0 1 2 3
885 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
886 +-+-+-+-+-------+-+-------------+-------------------------------+
887 |F|R|R|R| opcode|M| Payload len | Extended payload length |
888 |I|S|S|S| (4) |A| (7) | (16/64) +
889 |N|V|V|V| |S| | (if payload len==126/127) |
890 | |1|2|3| |K| | +
891 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
892 | Extended payload length continued, if payload len == 127 |
893 + - - - - - - - - - - - - - - - +-------------------------------+
894 | |Masking-key, if MASK set to 1 |
895 +-------------------------------+-------------------------------+
896 | Masking-key (continued) | Payload Data |
897 +-------------------------------- - - - - - - - - - - - - - - - +
898 : Payload Data continued ... :
899 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
900 | Payload Data continued ... |
901 +---------------------------------------------------------------+
902
903 * When reading these, the frames are possibly fragmented and interleaved with control frames
904 * the fragmented frames are not interleaved with data frames. Just control frames
905 */
906 public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]};
907 public WebsocketFrameHeader Header;
908 public byte[] WebSocketPayload;
909
910 public byte[] ToBytes()
911 {
912 Header.PayloadLen = (ulong)WebSocketPayload.Length;
913 return Header.ToBytes(WebSocketPayload);
914 }
915
916 }
917
918 public struct WebsocketFrameHeader
919 {
920 //public byte CurrentMaskIndex;
921 /// <summary>
922 /// The last frame in a sequence of fragmented frames or the one and only frame for this message.
923 /// </summary>
924 public bool IsEnd;
925
926 /// <summary>
927 /// Returns whether the payload data is masked or not. Data from Clients MUST be masked, Data from Servers MUST NOT be masked
928 /// </summary>
929 public bool IsMasked;
930
931 /// <summary>
932 /// A set of cryptologically sound random bytes XoR-ed against the payload octally. Looped
933 /// </summary>
934 public int Mask;
935 /*
936byt 0 1 2 3
937 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
938 +---------------+---------------+---------------+---------------+
939 | Octal 1 | Octal 2 | Octal 3 | Octal 4 |
940 +---------------+---------------+---------------+---------------+
941*/
942
943
944 public WebSocketReader.OpCode Opcode;
945
946 public UInt64 PayloadLen;
947 //public UInt64 PayloadLeft;
948 // Payload is X + Y
949 //public UInt64 ExtensionDataLength;
950 //public UInt64 ApplicationDataLength;
951 public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault();
952
953 public void SetDefault()
954 {
955
956 //CurrentMaskIndex = 0;
957 IsEnd = true;
958 IsMasked = true;
959 Mask = 0;
960 Opcode = WebSocketReader.OpCode.Close;
961 // PayloadLeft = 0;
962 PayloadLen = 0;
963 // ExtensionDataLength = 0;
964 // ApplicationDataLength = 0;
965
966 }
967
968 /// <summary>
969 /// Returns a byte array representing the Frame header
970 /// </summary>
971 /// <param name="payload">This is the frame data payload. The header describes the size of the payload.
972 /// If payload is null, a Zero sized payload is assumed</param>
973 /// <returns>Returns a byte array representing the frame header</returns>
974 public byte[] ToBytes(byte[] payload)
975 {
976 List<byte> result = new List<byte>();
977
978 // Squeeze in our opcode and our ending bit.
979 result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) ));
980
981 // Again with the three different byte interpretations of size..
982
983 //bytesize
984 if (PayloadLen <= 125)
985 {
986 result.Add((byte) PayloadLen);
987 } //Uint16
988 else if (PayloadLen <= ushort.MaxValue)
989 {
990 result.Add(126);
991 byte[] payloadLengthByte = BitConverter.GetBytes(Convert.ToUInt16(PayloadLen));
992 Array.Reverse(payloadLengthByte);
993 result.AddRange(payloadLengthByte);
994 } //UInt64
995 else
996 {
997 result.Add(127);
998 byte[] payloadLengthByte = BitConverter.GetBytes(PayloadLen);
999 Array.Reverse(payloadLengthByte);
1000 result.AddRange(payloadLengthByte);
1001 }
1002
1003 // Only add a payload if it's not null
1004 if (payload != null)
1005 {
1006 result.AddRange(payload);
1007 }
1008 return result.ToArray();
1009 }
1010
1011 /// <summary>
1012 /// A Helper method to define the defaults
1013 /// </summary>
1014 /// <returns></returns>
1015
1016 public static WebsocketFrameHeader HeaderDefault()
1017 {
1018 return new WebsocketFrameHeader
1019 {
1020 //CurrentMaskIndex = 0,
1021 IsEnd = false,
1022 IsMasked = true,
1023 Mask = 0,
1024 Opcode = WebSocketReader.OpCode.Close,
1025 //PayloadLeft = 0,
1026 PayloadLen = 0,
1027 // ExtensionDataLength = 0,
1028 // ApplicationDataLength = 0
1029 };
1030 }
1031 }
1032
1033 public delegate void DataDelegate(object sender, WebsocketDataEventArgs data);
1034
1035 public delegate void TextDelegate(object sender, WebsocketTextEventArgs text);
1036
1037 public delegate void PingDelegate(object sender, PingEventArgs pingdata);
1038
1039 public delegate void PongDelegate(object sender, PongEventArgs pongdata);
1040
1041 public delegate void RegularHttpRequestDelegate(object sender, RegularHttpRequestEvnetArgs request);
1042
1043 public delegate void UpgradeCompletedDelegate(object sender, UpgradeCompletedEventArgs completeddata);
1044
1045 public delegate void UpgradeFailedDelegate(object sender, UpgradeFailedEventArgs faileddata);
1046
1047 public delegate void CloseDelegate(object sender, CloseEventArgs closedata);
1048
1049 public delegate bool ValidateHandshake(string pWebOrigin, string pWebSocketKey, string pHost);
1050
1051
1052 public class WebsocketDataEventArgs : EventArgs
1053 {
1054 public byte[] Data;
1055 }
1056
1057 public class WebsocketTextEventArgs : EventArgs
1058 {
1059 public string Data;
1060 }
1061
1062 public class PingEventArgs : EventArgs
1063 {
1064 /// <summary>
1065 /// The ping event can arbitrarily contain data
1066 /// </summary>
1067 public byte[] Data;
1068 }
1069
1070 public class PongEventArgs : EventArgs
1071 {
1072 /// <summary>
1073 /// The pong event can arbitrarily contain data
1074 /// </summary>
1075 public byte[] Data;
1076
1077 public int PingResponseMS;
1078
1079 }
1080
1081 public class RegularHttpRequestEvnetArgs : EventArgs
1082 {
1083
1084 }
1085
1086 public class UpgradeCompletedEventArgs : EventArgs
1087 {
1088
1089 }
1090
1091 public class UpgradeFailedEventArgs : EventArgs
1092 {
1093
1094 }
1095
1096 public class CloseEventArgs : EventArgs
1097 {
1098
1099 }
1100
1101
1102}
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index ae7d515..cfd34bb 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -227,9 +227,16 @@ namespace OpenSim.Framework.Servers
227 handlers.AppendFormat("\t{0}\n", s); 227 handlers.AppendFormat("\t{0}\n", s);
228 228
229 handlers.AppendFormat("* HTTP:\n"); 229 handlers.AppendFormat("* HTTP:\n");
230 List<String> poll = httpServer.GetPollServiceHandlerKeys();
231 foreach (String s in httpServer.GetHTTPHandlerKeys()) 230 foreach (String s in httpServer.GetHTTPHandlerKeys())
232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); 231 handlers.AppendFormat("\t{0}\n", s);
232
233 handlers.AppendFormat("* HTTP (poll):\n");
234 foreach (String s in httpServer.GetPollServiceHandlerKeys())
235 handlers.AppendFormat("\t{0}\n", s);
236
237 handlers.AppendFormat("* JSONRPC:\n");
238 foreach (String s in httpServer.GetJsonRpcHandlerKeys())
239 handlers.AppendFormat("\t{0}\n", s);
233 240
234// handlers.AppendFormat("* Agent:\n"); 241// handlers.AppendFormat("* Agent:\n");
235// foreach (String s in httpServer.GetAgentHandlerKeys()) 242// foreach (String s in httpServer.GetAgentHandlerKeys())
diff --git a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
index 021f63c..792c62e 100644
--- a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index 9eb2281..1ff8aca 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{
@@ -110,6 +113,26 @@ namespace OpenSim.Framework.Servers
110 } 113 }
111 } 114 }
112 115
116 /// <summary>
117 /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
118 /// etc.).
119 /// </summary>
120 public void LogEnvironmentInformation()
121 {
122 // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
123 // XmlConfigurator calls first accross servers.
124 m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
125
126 m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
127
128 // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
129 // the clr version number doesn't match the project version number under Mono.
130 //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
131 m_log.InfoFormat(
132 "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
133 Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
134 }
135
113 public void RegisterCommonAppenders(IConfig startupConfig) 136 public void RegisterCommonAppenders(IConfig startupConfig)
114 { 137 {
115 ILoggerRepository repository = LogManager.GetRepository(); 138 ILoggerRepository repository = LogManager.GetRepository();
@@ -168,6 +191,9 @@ namespace OpenSim.Framework.Servers
168 "General", false, "show info", "show info", "Show general information about the server", HandleShow); 191 "General", false, "show info", "show info", "Show general information about the server", HandleShow);
169 192
170 m_console.Commands.AddCommand( 193 m_console.Commands.AddCommand(
194 "General", false, "show version", "show version", "Show server version", HandleShow);
195
196 m_console.Commands.AddCommand(
171 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); 197 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow);
172 198
173 m_console.Commands.AddCommand( 199 m_console.Commands.AddCommand(
@@ -206,6 +232,34 @@ namespace OpenSim.Framework.Servers
206 "General", false, "command-script", 232 "General", false, "command-script",
207 "command-script <script>", 233 "command-script <script>",
208 "Run a command script from file", HandleScript); 234 "Run a command script from file", HandleScript);
235
236 m_console.Commands.AddCommand(
237 "General", false, "show threads",
238 "show threads",
239 "Show thread status", HandleShow);
240
241 m_console.Commands.AddCommand(
242 "General", false, "threads abort",
243 "threads abort <thread-id>",
244 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
245
246 m_console.Commands.AddCommand(
247 "General", false, "threads show",
248 "threads show",
249 "Show thread status. Synonym for \"show threads\"",
250 (string module, string[] args) => Notice(GetThreadsReport()));
251
252 m_console.Commands.AddCommand(
253 "General", false, "force gc",
254 "force gc",
255 "Manually invoke runtime garbage collection. For debugging purposes",
256 HandleForceGc);
257 }
258
259 private void HandleForceGc(string module, string[] args)
260 {
261 Notice("Manually invoking runtime garbage collection");
262 GC.Collect();
209 } 263 }
210 264
211 public virtual void HandleShow(string module, string[] cmd) 265 public virtual void HandleShow(string module, string[] cmd)
@@ -222,9 +276,17 @@ namespace OpenSim.Framework.Servers
222 ShowInfo(); 276 ShowInfo();
223 break; 277 break;
224 278
279 case "version":
280 Notice(GetVersionText());
281 break;
282
225 case "uptime": 283 case "uptime":
226 Notice(GetUptimeReport()); 284 Notice(GetUptimeReport());
227 break; 285 break;
286
287 case "threads":
288 Notice(GetThreadsReport());
289 break;
228 } 290 }
229 } 291 }
230 292
@@ -537,6 +599,75 @@ namespace OpenSim.Framework.Servers
537 } 599 }
538 600
539 /// <summary> 601 /// <summary>
602 /// Get a report about the registered threads in this server.
603 /// </summary>
604 protected string GetThreadsReport()
605 {
606 // This should be a constant field.
607 string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
608
609 StringBuilder sb = new StringBuilder();
610 Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
611
612 sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
613
614 int timeNow = Environment.TickCount & Int32.MaxValue;
615
616 sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
617 sb.Append(Environment.NewLine);
618
619 foreach (Watchdog.ThreadWatchdogInfo twi in threads)
620 {
621 Thread t = twi.Thread;
622
623 sb.AppendFormat(
624 reportFormat,
625 t.ManagedThreadId,
626 t.Name,
627 timeNow - twi.LastTick,
628 timeNow - twi.FirstTick,
629 t.Priority,
630 t.ThreadState);
631
632 sb.Append("\n");
633 }
634
635 sb.Append("\n");
636
637 // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
638 // zero active threads.
639 int totalThreads = Process.GetCurrentProcess().Threads.Count;
640 if (totalThreads > 0)
641 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
642
643 sb.Append("Main threadpool (excluding script engine pools)\n");
644 sb.Append(Util.GetThreadPoolReport());
645
646 return sb.ToString();
647 }
648
649 public virtual void HandleThreadsAbort(string module, string[] cmd)
650 {
651 if (cmd.Length != 3)
652 {
653 MainConsole.Instance.Output("Usage: threads abort <thread-id>");
654 return;
655 }
656
657 int threadId;
658 if (!int.TryParse(cmd[2], out threadId))
659 {
660 MainConsole.Instance.Output("ERROR: Thread id must be an integer");
661 return;
662 }
663
664 if (Watchdog.AbortThread(threadId))
665 MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
666 else
667 MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
668 }
669
670 /// <summary>
540 /// Console output is only possible if a console has been established. 671 /// Console output is only possible if a console has been established.
541 /// That is something that cannot be determined within this class. So 672 /// That is something that cannot be determined within this class. So
542 /// all attempts to use the console MUST be verified. 673 /// 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..deae45c 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
@@ -69,6 +70,11 @@ namespace OpenSim.Framework.Servers.Tests
69 public void Close() { } 70 public void Close() { }
70 public bool EndWhenDone { get { return false;} set { return;}} 71 public bool EndWhenDone { get { return false;} set { return;}}
71 72
73 public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
74 {
75 return new HTTPNetworkContext();
76 }
77
72 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { }; 78 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
73 /// <summary> 79 /// <summary>
74 /// A request have been received in the context. 80 /// A request have been received in the context.
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/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index bb094ed..737c14d 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -29,7 +29,7 @@ namespace OpenSim
29{ 29{
30 public class VersionInfo 30 public class VersionInfo
31 { 31 {
32 private const string VERSION_NUMBER = "0.7.5CM"; 32 private const string VERSION_NUMBER = "0.7.6CM";
33 private const Flavour VERSION_FLAVOUR = Flavour.Dev; 33 private const Flavour VERSION_FLAVOUR = Flavour.Dev;
34 34
35 public enum Flavour 35 public enum Flavour
diff --git a/OpenSim/Framework/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..557f38e 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -45,6 +45,7 @@ using System.Text.RegularExpressions;
45using System.Xml; 45using System.Xml;
46using System.Threading; 46using System.Threading;
47using log4net; 47using log4net;
48using log4net.Appender;
48using Nini.Config; 49using Nini.Config;
49using Nwc.XmlRpc; 50using Nwc.XmlRpc;
50using OpenMetaverse; 51using OpenMetaverse;
@@ -53,6 +54,21 @@ using Amib.Threading;
53 54
54namespace OpenSim.Framework 55namespace OpenSim.Framework
55{ 56{
57 [Flags]
58 public enum PermissionMask : uint
59 {
60 None = 0,
61 Transfer = 1 << 13,
62 Modify = 1 << 14,
63 Copy = 1 << 15,
64 Export = 1 << 16,
65 Move = 1 << 19,
66 Damage = 1 << 20,
67 // All does not contain Export, which is special and must be
68 // explicitly given
69 All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
70 }
71
56 /// <summary> 72 /// <summary>
57 /// The method used by Util.FireAndForget for asynchronously firing events 73 /// The method used by Util.FireAndForget for asynchronously firing events
58 /// </summary> 74 /// </summary>
@@ -299,6 +315,25 @@ namespace OpenSim.Framework
299 x; 315 x;
300 } 316 }
301 317
318 // Clamp the maximum magnitude of a vector
319 public static Vector3 ClampV(Vector3 x, float max)
320 {
321 float lenSq = x.LengthSquared();
322 if (lenSq > (max * max))
323 {
324 x = x / x.Length() * max;
325 }
326
327 return x;
328 }
329
330 // Inclusive, within range test (true if equal to the endpoints)
331 public static bool InRange<T>(T x, T min, T max)
332 where T : IComparable<T>
333 {
334 return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
335 }
336
302 public static uint GetNextXferID() 337 public static uint GetNextXferID()
303 { 338 {
304 uint id = 0; 339 uint id = 0;
@@ -809,9 +844,22 @@ namespace OpenSim.Framework
809 return "."; 844 return ".";
810 } 845 }
811 846
847 public static string logFile()
848 {
849 foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
850 {
851 if (appender is FileAppender)
852 {
853 return ((FileAppender)appender).File;
854 }
855 }
856
857 return "./OpenSim.log";
858 }
859
812 public static string logDir() 860 public static string logDir()
813 { 861 {
814 return "."; 862 return Path.GetDirectoryName(logFile());
815 } 863 }
816 864
817 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html 865 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
@@ -842,7 +890,7 @@ namespace OpenSim.Framework
842 return FileName; 890 return FileName;
843 } 891 }
844 892
845 // Nini (config) related Methods 893 #region Nini (config) related Methods
846 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) 894 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
847 { 895 {
848 if (!File.Exists(fileName)) 896 if (!File.Exists(fileName))
@@ -865,6 +913,79 @@ namespace OpenSim.Framework
865 } 913 }
866 } 914 }
867 915
916 public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section)
917 {
918 // First, check the Startup section, the default section
919 IConfig cnf = config.Configs["Startup"];
920 if (cnf == null)
921 return string.Empty;
922 string val = cnf.GetString(varname, string.Empty);
923
924 // Then check for an overwrite of the default in the given section
925 if (!string.IsNullOrEmpty(section))
926 {
927 cnf = config.Configs[section];
928 if (cnf != null)
929 val = cnf.GetString(varname, val);
930 }
931
932 return val;
933 }
934
935 /// <summary>
936 /// Gets the value of a configuration variable by looking into
937 /// multiple sections in order. The latter sections overwrite
938 /// any values previously found.
939 /// </summary>
940 /// <typeparam name="T">Type of the variable</typeparam>
941 /// <param name="config">The configuration object</param>
942 /// <param name="varname">The configuration variable</param>
943 /// <param name="sections">Ordered sequence of sections to look at</param>
944 /// <returns></returns>
945 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections)
946 {
947 return GetConfigVarFromSections<T>(config, varname, sections, default(T));
948 }
949
950 /// <summary>
951 /// Gets the value of a configuration variable by looking into
952 /// multiple sections in order. The latter sections overwrite
953 /// any values previously found.
954 /// </summary>
955 /// <remarks>
956 /// If no value is found then the given default value is returned
957 /// </remarks>
958 /// <typeparam name="T">Type of the variable</typeparam>
959 /// <param name="config">The configuration object</param>
960 /// <param name="varname">The configuration variable</param>
961 /// <param name="sections">Ordered sequence of sections to look at</param>
962 /// <param name="val">Default value</param>
963 /// <returns></returns>
964 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections, object val)
965 {
966 foreach (string section in sections)
967 {
968 IConfig cnf = config.Configs[section];
969 if (cnf == null)
970 continue;
971
972 if (typeof(T) == typeof(String))
973 val = cnf.GetString(varname, (string)val);
974 else if (typeof(T) == typeof(Boolean))
975 val = cnf.GetBoolean(varname, (bool)val);
976 else if (typeof(T) == typeof(Int32))
977 val = cnf.GetInt(varname, (int)val);
978 else if (typeof(T) == typeof(float))
979 val = cnf.GetFloat(varname, (int)val);
980 else
981 m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T));
982 }
983
984 return (T)val;
985 }
986
987 #endregion
988
868 public static float Clip(float x, float min, float max) 989 public static float Clip(float x, float min, float max)
869 { 990 {
870 return Math.Min(Math.Max(x, min), max); 991 return Math.Min(Math.Max(x, min), max);
@@ -1651,7 +1772,13 @@ namespace OpenSim.Framework
1651 if (m_ThreadPool != null) 1772 if (m_ThreadPool != null)
1652 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1773 throw new InvalidOperationException("SmartThreadPool is already initialized");
1653 1774
1654 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); 1775 STPStartInfo startInfo = new STPStartInfo();
1776 startInfo.ThreadPoolName = "Util";
1777 startInfo.IdleTimeout = 2000;
1778 startInfo.MaxWorkerThreads = maxThreads;
1779 startInfo.MinWorkerThreads = 2;
1780
1781 m_ThreadPool = new SmartThreadPool(startInfo);
1655 } 1782 }
1656 1783
1657 public static int FireAndForgetCount() 1784 public static int FireAndForgetCount()
@@ -1724,7 +1851,7 @@ namespace OpenSim.Framework
1724 break; 1851 break;
1725 case FireAndForgetMethod.SmartThreadPool: 1852 case FireAndForgetMethod.SmartThreadPool:
1726 if (m_ThreadPool == null) 1853 if (m_ThreadPool == null)
1727 m_ThreadPool = new SmartThreadPool(2000, 15, 2); 1854 InitThreadPool(15);
1728 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1855 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
1729 break; 1856 break;
1730 case FireAndForgetMethod.Thread: 1857 case FireAndForgetMethod.Thread:
@@ -1753,12 +1880,16 @@ namespace OpenSim.Framework
1753 StringBuilder sb = new StringBuilder(); 1880 StringBuilder sb = new StringBuilder();
1754 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 1881 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1755 { 1882 {
1756 threadPoolUsed = "SmartThreadPool"; 1883 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
1757 maxThreads = m_ThreadPool.MaxThreads; 1884 if (m_ThreadPool != null)
1758 minThreads = m_ThreadPool.MinThreads; 1885 {
1759 inUseThreads = m_ThreadPool.InUseThreads; 1886 threadPoolUsed = "SmartThreadPool";
1760 allocatedThreads = m_ThreadPool.ActiveThreads; 1887 maxThreads = m_ThreadPool.MaxThreads;
1761 waitingCallbacks = m_ThreadPool.WaitingCallbacks; 1888 minThreads = m_ThreadPool.MinThreads;
1889 inUseThreads = m_ThreadPool.InUseThreads;
1890 allocatedThreads = m_ThreadPool.ActiveThreads;
1891 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1892 }
1762 } 1893 }
1763 else if ( 1894 else if (
1764 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 1895 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
@@ -1863,6 +1994,12 @@ namespace OpenSim.Framework
1863 /// </summary> 1994 /// </summary>
1864 public static void PrintCallStack() 1995 public static void PrintCallStack()
1865 { 1996 {
1997 PrintCallStack(m_log.DebugFormat);
1998 }
1999
2000 public delegate void DebugPrinter(string msg, params Object[] parm);
2001 public static void PrintCallStack(DebugPrinter printer)
2002 {
1866 StackTrace stackTrace = new StackTrace(true); // get call stack 2003 StackTrace stackTrace = new StackTrace(true); // get call stack
1867 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) 2004 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1868 2005
@@ -1870,7 +2007,7 @@ namespace OpenSim.Framework
1870 foreach (StackFrame stackFrame in stackFrames) 2007 foreach (StackFrame stackFrame in stackFrames)
1871 { 2008 {
1872 MethodBase mb = stackFrame.GetMethod(); 2009 MethodBase mb = stackFrame.GetMethod();
1873 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name 2010 printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1874 } 2011 }
1875 } 2012 }
1876 2013
@@ -2096,5 +2233,124 @@ namespace OpenSim.Framework
2096 return firstName + "." + lastName + " " + "@" + uri.Authority; 2233 return firstName + "." + lastName + " " + "@" + uri.Authority;
2097 } 2234 }
2098 #endregion 2235 #endregion
2236
2237 /// <summary>
2238 /// Escapes the special characters used in "LIKE".
2239 /// </summary>
2240 /// <remarks>
2241 /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz"
2242 /// </remarks>
2243 public static string EscapeForLike(string str)
2244 {
2245 return str.Replace("_", "\\_").Replace("%", "\\%");
2246 }
2247 }
2248
2249 public class DoubleQueue<T> where T:class
2250 {
2251 private Queue<T> m_lowQueue = new Queue<T>();
2252 private Queue<T> m_highQueue = new Queue<T>();
2253
2254 private object m_syncRoot = new object();
2255 private Semaphore m_s = new Semaphore(0, 1);
2256
2257 public DoubleQueue()
2258 {
2259 }
2260
2261 public virtual int Count
2262 {
2263 get { return m_highQueue.Count + m_lowQueue.Count; }
2264 }
2265
2266 public virtual void Enqueue(T data)
2267 {
2268 Enqueue(m_lowQueue, data);
2269 }
2270
2271 public virtual void EnqueueLow(T data)
2272 {
2273 Enqueue(m_lowQueue, data);
2274 }
2275
2276 public virtual void EnqueueHigh(T data)
2277 {
2278 Enqueue(m_highQueue, data);
2279 }
2280
2281 private void Enqueue(Queue<T> q, T data)
2282 {
2283 lock (m_syncRoot)
2284 {
2285 m_lowQueue.Enqueue(data);
2286 m_s.WaitOne(0);
2287 m_s.Release();
2288 }
2289 }
2290
2291 public virtual T Dequeue()
2292 {
2293 return Dequeue(Timeout.Infinite);
2294 }
2295
2296 public virtual T Dequeue(int tmo)
2297 {
2298 return Dequeue(TimeSpan.FromMilliseconds(tmo));
2299 }
2300
2301 public virtual T Dequeue(TimeSpan wait)
2302 {
2303 T res = null;
2304
2305 if (!Dequeue(wait, ref res))
2306 return null;
2307
2308 return res;
2309 }
2310
2311 public bool Dequeue(int timeout, ref T res)
2312 {
2313 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
2314 }
2315
2316 public bool Dequeue(TimeSpan wait, ref T res)
2317 {
2318 if (!m_s.WaitOne(wait))
2319 return false;
2320
2321 lock (m_syncRoot)
2322 {
2323 if (m_highQueue.Count > 0)
2324 res = m_highQueue.Dequeue();
2325 else
2326 res = m_lowQueue.Dequeue();
2327
2328 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
2329 return true;
2330
2331 try
2332 {
2333 m_s.Release();
2334 }
2335 catch
2336 {
2337 }
2338
2339 return true;
2340 }
2341 }
2342
2343 public virtual void Clear()
2344 {
2345
2346 lock (m_syncRoot)
2347 {
2348 // Make sure sem count is 0
2349 m_s.WaitOne(0);
2350
2351 m_lowQueue.Clear();
2352 m_highQueue.Clear();
2353 }
2354 }
2099 } 2355 }
2100} 2356}
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index b85d93d..bf57fd4 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -228,8 +228,8 @@ namespace OpenSim.Framework
228 errorMessage = we.Message; 228 errorMessage = we.Message;
229 if (we.Status == WebExceptionStatus.ProtocolError) 229 if (we.Status == WebExceptionStatus.ProtocolError)
230 { 230 {
231 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 231 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
232 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 232 errorMessage = String.Format("[{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription);
233 } 233 }
234 } 234 }
235 catch (Exception ex) 235 catch (Exception ex)
@@ -388,8 +388,8 @@ namespace OpenSim.Framework
388 errorMessage = we.Message; 388 errorMessage = we.Message;
389 if (we.Status == WebExceptionStatus.ProtocolError) 389 if (we.Status == WebExceptionStatus.ProtocolError)
390 { 390 {
391 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 391 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
392 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 392 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription);
393 } 393 }
394 } 394 }
395 catch (Exception ex) 395 catch (Exception ex)
@@ -837,15 +837,16 @@ namespace OpenSim.Framework
837 { 837 {
838 if (e.Response is HttpWebResponse) 838 if (e.Response is HttpWebResponse)
839 { 839 {
840 HttpWebResponse httpResponse = (HttpWebResponse)e.Response; 840 using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response)
841 841 {
842 if (httpResponse.StatusCode != HttpStatusCode.NotFound) 842 if (httpResponse.StatusCode != HttpStatusCode.NotFound)
843 { 843 {
844 // We don't appear to be handling any other status codes, so log these feailures to that 844 // We don't appear to be handling any other status codes, so log these feailures to that
845 // people don't spend unnecessary hours hunting phantom bugs. 845 // people don't spend unnecessary hours hunting phantom bugs.
846 m_log.DebugFormat( 846 m_log.DebugFormat(
847 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", 847 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}",
848 verb, requestUrl, httpResponse.StatusCode); 848 verb, requestUrl, httpResponse.StatusCode);
849 }
849 } 850 }
850 } 851 }
851 } 852 }
@@ -995,11 +996,9 @@ namespace OpenSim.Framework
995 Stream respStream = null; 996 Stream respStream = null;
996 try 997 try
997 { 998 {
998 respStream = resp.GetResponseStream(); 999 using (respStream = resp.GetResponseStream())
999 using (StreamReader reader = new StreamReader(respStream)) 1000 using (StreamReader reader = new StreamReader(respStream))
1000 { 1001 respstring = reader.ReadToEnd();
1001 respstring = reader.ReadToEnd();
1002 }
1003 } 1002 }
1004 catch (Exception e) 1003 catch (Exception e)
1005 { 1004 {
@@ -1142,10 +1141,11 @@ namespace OpenSim.Framework
1142 { 1141 {
1143 if (resp.ContentLength != 0) 1142 if (resp.ContentLength != 0)
1144 { 1143 {
1145 Stream respStream = resp.GetResponseStream(); 1144 using (Stream respStream = resp.GetResponseStream())
1146 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); 1145 {
1147 deserial = (TResponse)deserializer.Deserialize(respStream); 1146 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
1148 respStream.Close(); 1147 deserial = (TResponse)deserializer.Deserialize(respStream);
1148 }
1149 } 1149 }
1150 else 1150 else
1151 { 1151 {
@@ -1157,14 +1157,15 @@ namespace OpenSim.Framework
1157 } 1157 }
1158 catch (WebException e) 1158 catch (WebException e)
1159 { 1159 {
1160 HttpWebResponse hwr = (HttpWebResponse)e.Response; 1160 using (HttpWebResponse hwr = (HttpWebResponse)e.Response)
1161 1161 {
1162 if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound) 1162 if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound)
1163 return deserial; 1163 return deserial;
1164 else 1164 else
1165 m_log.ErrorFormat( 1165 m_log.ErrorFormat(
1166 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", 1166 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}",
1167 verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); 1167 verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace);
1168 }
1168 } 1169 }
1169 catch (System.InvalidOperationException) 1170 catch (System.InvalidOperationException)
1170 { 1171 {
diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs
index 0f90d37..c3e7ec2 100644
--- a/OpenSim/Region/Application/Application.cs
+++ b/OpenSim/Region/Application/Application.cs
@@ -102,17 +102,50 @@ namespace OpenSim
102 m_log.InfoFormat( 102 m_log.InfoFormat(
103 "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); 103 "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
104 104
105 // Increase the number of IOCP threads available. Mono defaults to a tragically low number 105 // Verify the Threadpool allocates or uses enough worker and IO completion threads
106 // .NET 2.0 workerthreads default to 50 * numcores
107 // .NET 3.0 workerthreads defaults to 250 * numcores
108 // .NET 4.0 workerthreads are dynamic based on bitness and OS resources
109 // Max IO Completion threads are 1000 on all 3 CLRs.
110 int workerThreadsMin = 500;
111 int workerThreadsMax = 1000; // may need further adjustment to match other CLR
112 int iocpThreadsMin = 1000;
113 int iocpThreadsMax = 2000; // may need further adjustment to match other CLR
106 int workerThreads, iocpThreads; 114 int workerThreads, iocpThreads;
107 System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); 115 System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
108 m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads); 116 m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads);
109 if (workerThreads < 500 || iocpThreads < 1000) 117 if (workerThreads < workerThreadsMin)
110 { 118 {
111 workerThreads = 500; 119 workerThreads = workerThreadsMin;
112 iocpThreads = 1000; 120 m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to worker threads to {0}",workerThreads);
113 m_log.Info("[OPENSIM MAIN]: Bumping up to 500 worker threads and 1000 IOCP threads");
114 System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads);
115 } 121 }
122 if (workerThreads > workerThreadsMax)
123 {
124 workerThreads = workerThreadsMax;
125 m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads);
126 }
127 // Increase the number of IOCP threads available.
128 // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17)
129 if (iocpThreads < iocpThreadsMin)
130 {
131 iocpThreads = iocpThreadsMin;
132 m_log.InfoFormat("[OPENSIM MAIN]: Bumping up IO completion threads to {0}",iocpThreads);
133 }
134 // Make sure we don't overallocate IOCP threads and thrash system resources
135 if ( iocpThreads > iocpThreadsMax )
136 {
137 iocpThreads = iocpThreadsMax;
138 m_log.InfoFormat("[OPENSIM MAIN]: Limiting IO completion threads to {0}",iocpThreads);
139 }
140 // set the resulting worker and IO completion thread counts back to ThreadPool
141 if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
142 {
143 m_log.InfoFormat("[OPENSIM MAIN]: Threadpool set to {0} worker threads and {1} IO completion threads", workerThreads, iocpThreads);
144 }
145 else
146 {
147 m_log.Info("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
148 }
116 149
117 // Check if the system is compatible with OpenSimulator. 150 // Check if the system is compatible with OpenSimulator.
118 // Ensures that the minimum system requirements are met 151 // Ensures that the minimum system requirements are met
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 08e4023..a7e7d03 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Diagnostics; 31using System.Diagnostics;
32using System.IO; 32using System.IO;
33using System.Linq;
33using System.Reflection; 34using System.Reflection;
34using System.Text; 35using System.Text;
35using System.Text.RegularExpressions; 36using System.Text.RegularExpressions;
@@ -158,6 +159,7 @@ namespace OpenSim
158 159
159 MainConsole.Instance = m_console; 160 MainConsole.Instance = m_console;
160 161
162 LogEnvironmentInformation();
161 RegisterCommonAppenders(Config.Configs["Startup"]); 163 RegisterCommonAppenders(Config.Configs["Startup"]);
162 RegisterConsoleCommands(); 164 RegisterConsoleCommands();
163 165
@@ -236,18 +238,6 @@ namespace OpenSim
236 + "If an avatar name is given then only packets from that avatar are logged", 238 + "If an avatar name is given then only packets from that avatar are logged",
237 Debug); 239 Debug);
238 240
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", 241 m_console.Commands.AddCommand("General", false, "change region",
252 "change region <region name>", 242 "change region <region name>",
253 "Change current console region", ChangeSelectedRegion); 243 "Change current console region", ChangeSelectedRegion);
@@ -744,31 +734,6 @@ namespace OpenSim
744 734
745 break; 735 break;
746 736
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: 737 default:
773 MainConsole.Instance.Output("Unknown debug command"); 738 MainConsole.Instance.Output("Unknown debug command");
774 break; 739 break;
@@ -845,16 +810,28 @@ namespace OpenSim
845 break; 810 break;
846 811
847 case "modules": 812 case "modules":
848 SceneManager.ForEachScene( 813 SceneManager.ForEachSelectedScene(
849 delegate(Scene scene) { 814 scene =>
850 MainConsole.Instance.Output("Loaded region modules in" + scene.RegionInfo.RegionName + " are:");
851 foreach (IRegionModuleBase module in scene.RegionModules.Values)
852 { 815 {
853 Type type = module.GetType().GetInterface("ISharedRegionModule"); 816 MainConsole.Instance.OutputFormat("Loaded region modules in {0} are:", scene.Name);
854 string module_type = type != null ? "Shared" : "Non-Shared"; 817
855 MainConsole.Instance.OutputFormat("New Region Module ({0}): {1}", module_type, module.Name); 818 List<IRegionModuleBase> sharedModules = new List<IRegionModuleBase>();
819 List<IRegionModuleBase> nonSharedModules = new List<IRegionModuleBase>();
820
821 foreach (IRegionModuleBase module in scene.RegionModules.Values)
822 {
823 if (module.GetType().GetInterface("ISharedRegionModule") != null)
824 nonSharedModules.Add(module);
825 else
826 sharedModules.Add(module);
827 }
828
829 foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name))
830 MainConsole.Instance.OutputFormat("New Region Module (Shared): {0}", module.Name);
831
832 foreach (IRegionModuleBase module in sharedModules.OrderBy(m => m.Name))
833 MainConsole.Instance.OutputFormat("New Region Module (Non-Shared): {0}", module.Name);
856 } 834 }
857 }
858 ); 835 );
859 836
860 MainConsole.Instance.Output(""); 837 MainConsole.Instance.Output("");
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index bed9a49..7361f50 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -331,7 +331,7 @@ namespace OpenSim
331 /// <param name="regionInfo"></param> 331 /// <param name="regionInfo"></param>
332 /// <param name="portadd_flag"></param> 332 /// <param name="portadd_flag"></param>
333 /// <returns></returns> 333 /// <returns></returns>
334 public IClientNetworkServer CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene) 334 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene)
335 { 335 {
336 return CreateRegion(regionInfo, portadd_flag, false, out scene); 336 return CreateRegion(regionInfo, portadd_flag, false, out scene);
337 } 337 }
@@ -341,7 +341,7 @@ namespace OpenSim
341 /// </summary> 341 /// </summary>
342 /// <param name="regionInfo"></param> 342 /// <param name="regionInfo"></param>
343 /// <returns></returns> 343 /// <returns></returns>
344 public IClientNetworkServer CreateRegion(RegionInfo regionInfo, out IScene scene) 344 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, out IScene scene)
345 { 345 {
346 return CreateRegion(regionInfo, false, true, out scene); 346 return CreateRegion(regionInfo, false, true, out scene);
347 } 347 }
@@ -353,7 +353,7 @@ namespace OpenSim
353 /// <param name="portadd_flag"></param> 353 /// <param name="portadd_flag"></param>
354 /// <param name="do_post_init"></param> 354 /// <param name="do_post_init"></param>
355 /// <returns></returns> 355 /// <returns></returns>
356 public IClientNetworkServer CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene) 356 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene)
357 { 357 {
358 int port = regionInfo.InternalEndPoint.Port; 358 int port = regionInfo.InternalEndPoint.Port;
359 359
@@ -378,8 +378,8 @@ namespace OpenSim
378 Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName); 378 Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName);
379 } 379 }
380 380
381 IClientNetworkServer clientServer; 381 List<IClientNetworkServer> clientServers;
382 Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServer); 382 Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServers);
383 383
384 m_log.Info("[MODULES]: Loading Region's modules (old style)"); 384 m_log.Info("[MODULES]: Loading Region's modules (old style)");
385 385
@@ -483,8 +483,11 @@ namespace OpenSim
483 483
484 if (m_autoCreateClientStack) 484 if (m_autoCreateClientStack)
485 { 485 {
486 m_clientServers.Add(clientServer); 486 foreach (IClientNetworkServer clientserver in clientServers)
487 clientServer.Start(); 487 {
488 m_clientServers.Add(clientserver);
489 clientserver.Start();
490 }
488 } 491 }
489 492
490 if (scene.SnmpService != null) 493 if (scene.SnmpService != null)
@@ -504,7 +507,7 @@ namespace OpenSim
504 scene.Start(); 507 scene.Start();
505 scene.StartScripts(); 508 scene.StartScripts();
506 509
507 return clientServer; 510 return clientServers;
508 } 511 }
509 512
510 /// <summary> 513 /// <summary>
@@ -725,7 +728,7 @@ namespace OpenSim
725 /// <param name="regionInfo"></param> 728 /// <param name="regionInfo"></param>
726 /// <param name="clientServer"> </param> 729 /// <param name="clientServer"> </param>
727 /// <returns></returns> 730 /// <returns></returns>
728 protected Scene SetupScene(RegionInfo regionInfo, out IClientNetworkServer clientServer) 731 protected Scene SetupScene(RegionInfo regionInfo, out List<IClientNetworkServer> clientServer)
729 { 732 {
730 return SetupScene(regionInfo, 0, null, out clientServer); 733 return SetupScene(regionInfo, 0, null, out clientServer);
731 } 734 }
@@ -739,8 +742,10 @@ namespace OpenSim
739 /// <param name="clientServer"> </param> 742 /// <param name="clientServer"> </param>
740 /// <returns></returns> 743 /// <returns></returns>
741 protected Scene SetupScene( 744 protected Scene SetupScene(
742 RegionInfo regionInfo, int proxyOffset, IConfigSource configSource, out IClientNetworkServer clientServer) 745 RegionInfo regionInfo, int proxyOffset, IConfigSource configSource, out List<IClientNetworkServer> clientServer)
743 { 746 {
747 List<IClientNetworkServer> clientNetworkServers = null;
748
744 AgentCircuitManager circuitManager = new AgentCircuitManager(); 749 AgentCircuitManager circuitManager = new AgentCircuitManager();
745 IPAddress listenIP = regionInfo.InternalEndPoint.Address; 750 IPAddress listenIP = regionInfo.InternalEndPoint.Address;
746 //if (!IPAddress.TryParse(regionInfo.InternalEndPoint, out listenIP)) 751 //if (!IPAddress.TryParse(regionInfo.InternalEndPoint, out listenIP))
@@ -750,8 +755,7 @@ namespace OpenSim
750 755
751 if (m_autoCreateClientStack) 756 if (m_autoCreateClientStack)
752 { 757 {
753 clientServer 758 clientNetworkServers = m_clientStackManager.CreateServers(
754 = m_clientStackManager.CreateServer(
755 listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, configSource, 759 listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, configSource,
756 circuitManager); 760 circuitManager);
757 } 761 }
@@ -766,9 +770,12 @@ namespace OpenSim
766 770
767 if (m_autoCreateClientStack) 771 if (m_autoCreateClientStack)
768 { 772 {
769 clientServer.AddScene(scene); 773 foreach (IClientNetworkServer clientnetserver in clientNetworkServers)
774 {
775 clientnetserver.AddScene(scene);
776 }
770 } 777 }
771 778 clientServer = clientNetworkServers;
772 scene.LoadWorldMap(); 779 scene.LoadWorldMap();
773 780
774 scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName); 781 scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName);
@@ -791,7 +798,7 @@ namespace OpenSim
791 798
792 return new Scene( 799 return new Scene(
793 regionInfo, circuitManager, sceneGridService, 800 regionInfo, circuitManager, sceneGridService,
794 simDataService, estateDataService, false, 801 simDataService, estateDataService,
795 Config, m_version); 802 Config, m_version);
796 } 803 }
797 804
diff --git a/OpenSim/Region/ClientStack/ClientStackManager.cs b/OpenSim/Region/ClientStack/ClientStackManager.cs
index 84ea0b3..299aabd 100644
--- a/OpenSim/Region/ClientStack/ClientStackManager.cs
+++ b/OpenSim/Region/ClientStack/ClientStackManager.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
29using System.Net; 30using System.Net;
30using System.Reflection; 31using System.Reflection;
31using log4net; 32using log4net;
@@ -38,39 +39,53 @@ namespace OpenSim.Region.ClientStack
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 Type plugin; 42 private List<Type> plugin = new List<Type>();
42 private Assembly pluginAssembly; 43 private List<Assembly> pluginAssembly = new List<Assembly>();
43 44
44 public ClientStackManager(string dllName) 45 public ClientStackManager(string pDllName)
45 { 46 {
46 m_log.Info("[CLIENTSTACK]: Attempting to load " + dllName); 47 List<string> clientstacks = new List<string>();
47 48 if (pDllName.Contains(","))
48 try 49 {
50 clientstacks = new List<string>(pDllName.Split(','));
51 }
52 else
49 { 53 {
50 plugin = null; 54 clientstacks.Add(pDllName);
51 pluginAssembly = Assembly.LoadFrom(dllName); 55 }
56 foreach (string dllName in clientstacks)
57 {
58 m_log.Info("[CLIENTSTACK]: Attempting to load " + dllName);
52 59
53 foreach (Type pluginType in pluginAssembly.GetTypes()) 60 try
54 { 61 {
55 if (pluginType.IsPublic) 62 //plugin = null;
56 { 63 Assembly itemAssembly = Assembly.LoadFrom(dllName);
57 Type typeInterface = pluginType.GetInterface("IClientNetworkServer", true); 64 pluginAssembly.Add(itemAssembly);
58 65
59 if (typeInterface != null) 66 foreach (Type pluginType in itemAssembly.GetTypes())
67 {
68 if (pluginType.IsPublic)
60 { 69 {
61 m_log.Info("[CLIENTSTACK]: Added IClientNetworkServer Interface"); 70 Type typeInterface = pluginType.GetInterface("IClientNetworkServer", true);
62 plugin = pluginType; 71
63 return; 72 if (typeInterface != null)
73 {
74 m_log.Info("[CLIENTSTACK]: Added IClientNetworkServer Interface");
75 plugin.Add(pluginType);
76 break;
77 }
64 } 78 }
65 } 79 }
66 } 80 }
67 } catch (ReflectionTypeLoadException e) 81 catch (ReflectionTypeLoadException e)
68 {
69 foreach (Exception e2 in e.LoaderExceptions)
70 { 82 {
71 m_log.Error(e2.ToString()); 83 foreach (Exception e2 in e.LoaderExceptions)
84 {
85 m_log.Error(e2.ToString());
86 }
87 throw e;
72 } 88 }
73 throw e;
74 } 89 }
75 } 90 }
76 91
@@ -84,11 +99,11 @@ namespace OpenSim.Region.ClientStack
84 /// <param name="assetCache"></param> 99 /// <param name="assetCache"></param>
85 /// <param name="authenticateClass"></param> 100 /// <param name="authenticateClass"></param>
86 /// <returns></returns> 101 /// <returns></returns>
87 public IClientNetworkServer CreateServer( 102 public List<IClientNetworkServer> CreateServers(
88 IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, 103 IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port,
89 AgentCircuitManager authenticateClass) 104 AgentCircuitManager authenticateClass)
90 { 105 {
91 return CreateServer( 106 return CreateServers(
92 _listenIP, ref port, proxyPortOffset, allow_alternate_port, null, authenticateClass); 107 _listenIP, ref port, proxyPortOffset, allow_alternate_port, null, authenticateClass);
93 } 108 }
94 109
@@ -105,20 +120,24 @@ namespace OpenSim.Region.ClientStack
105 /// <param name="assetCache"></param> 120 /// <param name="assetCache"></param>
106 /// <param name="authenticateClass"></param> 121 /// <param name="authenticateClass"></param>
107 /// <returns></returns> 122 /// <returns></returns>
108 public IClientNetworkServer CreateServer( 123 public List<IClientNetworkServer> CreateServers(
109 IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, IConfigSource configSource, 124 IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, IConfigSource configSource,
110 AgentCircuitManager authenticateClass) 125 AgentCircuitManager authenticateClass)
111 { 126 {
127 List<IClientNetworkServer> servers = new List<IClientNetworkServer>();
112 if (plugin != null) 128 if (plugin != null)
113 { 129 {
114 IClientNetworkServer server = 130 for (int i = 0; i < plugin.Count; i++)
115 (IClientNetworkServer)Activator.CreateInstance(pluginAssembly.GetType(plugin.ToString())); 131 {
116 132 IClientNetworkServer server =
117 server.Initialise( 133 (IClientNetworkServer) Activator.CreateInstance(pluginAssembly[i].GetType(plugin[i].ToString()));
118 _listenIP, ref port, proxyPortOffset, allow_alternate_port, 134
119 configSource, authenticateClass); 135 server.Initialise(
120 136 _listenIP, ref port, proxyPortOffset, allow_alternate_port,
121 return server; 137 configSource, authenticateClass);
138 servers.Add(server);
139 }
140 return servers;
122 } 141 }
123 142
124 m_log.Error("[CLIENTSTACK]: Couldn't initialize a new server"); 143 m_log.Error("[CLIENTSTACK]: Couldn't initialize a new server");
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index b06788b..921d3bf 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -50,6 +50,7 @@ using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 50using Caps = OpenSim.Framework.Capabilities.Caps;
51using OSDArray = OpenMetaverse.StructuredData.OSDArray; 51using OSDArray = OpenMetaverse.StructuredData.OSDArray;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap; 52using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53using PermissionMask = OpenSim.Framework.PermissionMask;
53 54
54namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
55{ 56{
@@ -105,7 +106,6 @@ namespace OpenSim.Region.ClientStack.Linden
105 private static readonly string m_ResourceCostSelectedPath = "0103/"; 106 private static readonly string m_ResourceCostSelectedPath = "0103/";
106 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
107 108
108
109 // These are callbacks which will be setup by the scene so that we can update scene data when we 109 // These are callbacks which will be setup by the scene so that we can update scene data when we
110 // receive capability calls 110 // receive capability calls
111 public NewInventoryItem AddNewInventoryItem = null; 111 public NewInventoryItem AddNewInventoryItem = null;
@@ -343,6 +343,9 @@ namespace OpenSim.Region.ClientStack.Linden
343 m_log.DebugFormat( 343 m_log.DebugFormat(
344 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 344 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
345 345
346 if (!m_HostCapsObj.WaitForActivation())
347 return string.Empty;
348
346 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 349 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
347 { 350 {
348 m_log.WarnFormat( 351 m_log.WarnFormat(
@@ -828,9 +831,9 @@ namespace OpenSim.Region.ClientStack.Linden
828 texitem.Folder = texturesFolder; 831 texitem.Folder = texturesFolder;
829 832
830 texitem.CurrentPermissions 833 texitem.CurrentPermissions
831 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); 834 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
832 835
833 texitem.BasePermissions = (uint)PermissionMask.All; 836 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
834 texitem.EveryOnePermissions = 0; 837 texitem.EveryOnePermissions = 0;
835 texitem.NextPermissions = (uint)PermissionMask.All; 838 texitem.NextPermissions = (uint)PermissionMask.All;
836 texitem.CreationDate = Util.UnixTimeSinceEpoch(); 839 texitem.CreationDate = Util.UnixTimeSinceEpoch();
@@ -1095,9 +1098,9 @@ namespace OpenSim.Region.ClientStack.Linden
1095 else 1098 else
1096 { 1099 {
1097 item.CurrentPermissions 1100 item.CurrentPermissions
1098 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); 1101 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
1099 1102
1100 item.BasePermissions = (uint)PermissionMask.All; 1103 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1101 item.EveryOnePermissions = 0; 1104 item.EveryOnePermissions = 0;
1102 item.NextPermissions = (uint)PermissionMask.All; 1105 item.NextPermissions = (uint)PermissionMask.All;
1103 } 1106 }
@@ -1317,7 +1320,7 @@ namespace OpenSim.Region.ClientStack.Linden
1317 object_data["PhysicsShapeType"] = obj.PhysicsShapeType; 1320 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
1318 object_data["Density"] = obj.Density; 1321 object_data["Density"] = obj.Density;
1319 object_data["Friction"] = obj.Friction; 1322 object_data["Friction"] = obj.Friction;
1320 object_data["Restitution"] = obj.Bounciness; 1323 object_data["Restitution"] = obj.Restitution;
1321 object_data["GravityMultiplier"] = obj.GravityModifier; 1324 object_data["GravityMultiplier"] = obj.GravityModifier;
1322 1325
1323 resp[uuid.ToString()] = object_data; 1326 resp[uuid.ToString()] = object_data;
@@ -1446,7 +1449,7 @@ namespace OpenSim.Region.ClientStack.Linden
1446 string param, IOSHttpRequest httpRequest, 1449 string param, IOSHttpRequest httpRequest,
1447 IOSHttpResponse httpResponse) 1450 IOSHttpResponse httpResponse)
1448 { 1451 {
1449 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); 1452// OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1450 OSDMap resp = new OSDMap(); 1453 OSDMap resp = new OSDMap();
1451 1454
1452 OSDMap accessPrefs = new OSDMap(); 1455 OSDMap accessPrefs = new OSDMap();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 986a665..37285e3 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -97,6 +97,14 @@ namespace OpenSim.Region.ClientStack.Linden
97 + " >= 1 - turns on outgoing event logging\n" 97 + " >= 1 - turns on outgoing event logging\n"
98 + " >= 2 - turns on poll notification", 98 + " >= 2 - turns on poll notification",
99 HandleDebugEq); 99 HandleDebugEq);
100
101 MainConsole.Instance.Commands.AddCommand(
102 "Debug",
103 false,
104 "show eq",
105 "show eq",
106 "Show contents of event queues for logged in avatars. Used for debugging.",
107 HandleShowEq);
100 } 108 }
101 109
102 public void RemoveRegion(Scene scene) 110 public void RemoveRegion(Scene scene)
@@ -138,7 +146,7 @@ namespace OpenSim.Region.ClientStack.Linden
138 146
139 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) 147 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
140 { 148 {
141 MainConsole.Instance.OutputFormat("Usage: debug eq [0|1]"); 149 MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]");
142 } 150 }
143 else 151 else
144 { 152 {
@@ -148,6 +156,21 @@ namespace OpenSim.Region.ClientStack.Linden
148 } 156 }
149 } 157 }
150 158
159 protected void HandleShowEq(string module, string[] args)
160 {
161 MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name);
162
163 lock (queues)
164 {
165 foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues)
166 {
167 MainConsole.Instance.OutputFormat(
168 "For agent {0} there are {1} messages queued for send.",
169 kvp.Key, kvp.Value.Count);
170 }
171 }
172 }
173
151 /// <summary> 174 /// <summary>
152 /// Always returns a valid queue 175 /// Always returns a valid queue
153 /// </summary> 176 /// </summary>
@@ -467,8 +490,8 @@ namespace OpenSim.Region.ClientStack.Linden
467 responsedata["content_type"] = "text/plain"; 490 responsedata["content_type"] = "text/plain";
468 responsedata["keepalive"] = false; 491 responsedata["keepalive"] = false;
469 responsedata["reusecontext"] = false; 492 responsedata["reusecontext"] = false;
470 responsedata["str_response_string"] = "Upstream error: "; 493 responsedata["str_response_string"] = "<llsd></llsd>";
471 responsedata["error_status_text"] = "Upstream error:"; 494 responsedata["error_status_text"] = "<llsd></llsd>";
472 responsedata["http_protocol_version"] = "HTTP/1.0"; 495 responsedata["http_protocol_version"] = "HTTP/1.0";
473 return responsedata; 496 return responsedata;
474 } 497 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index d604cf6..141af8a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -44,13 +44,15 @@ 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
51 [SetUp] 51 [SetUp]
52 public void SetUp() 52 public override void SetUp()
53 { 53 {
54 base.SetUp();
55
54 uint port = 9999; 56 uint port = 9999;
55 uint sslPort = 9998; 57 uint sslPort = 9998;
56 58
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index d4dbfb9..a42c96c 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -56,6 +56,7 @@ namespace OpenSim.Region.ClientStack.Linden
56 public PollServiceTextureEventArgs thepoll; 56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID; 57 public UUID reqID;
58 public Hashtable request; 58 public Hashtable request;
59 public bool send503;
59 } 60 }
60 61
61 public class aPollResponse 62 public class aPollResponse
@@ -244,7 +245,19 @@ namespace OpenSim.Region.ClientStack.Linden
244 reqinfo.thepoll = this; 245 reqinfo.thepoll = this;
245 reqinfo.reqID = x; 246 reqinfo.reqID = x;
246 reqinfo.request = y; 247 reqinfo.request = y;
248 reqinfo.send503 = false;
247 249
250 lock (responses)
251 {
252 if (responses.Count > 0)
253 {
254 if (m_queue.Count >= 4)
255 {
256 // Never allow more than 4 fetches to wait
257 reqinfo.send503 = true;
258 }
259 }
260 }
248 m_queue.Enqueue(reqinfo); 261 m_queue.Enqueue(reqinfo);
249 }; 262 };
250 263
@@ -276,6 +289,22 @@ namespace OpenSim.Region.ClientStack.Linden
276 289
277 UUID requestID = requestinfo.reqID; 290 UUID requestID = requestinfo.reqID;
278 291
292 if (requestinfo.send503)
293 {
294 response = new Hashtable();
295
296 response["int_response_code"] = 503;
297 response["str_response_string"] = "Throttled";
298 response["content_type"] = "text/plain";
299 response["keepalive"] = false;
300 response["reusecontext"] = false;
301
302 lock (responses)
303 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
304
305 return;
306 }
307
279 // If the avatar is gone, don't bother to get the texture 308 // If the avatar is gone, don't bother to get the texture
280 if (m_scene.GetScenePresence(Id) == null) 309 if (m_scene.GetScenePresence(Id) == null)
281 { 310 {
@@ -385,6 +414,9 @@ namespace OpenSim.Region.ClientStack.Linden
385 GetTextureModule.aPollResponse response; 414 GetTextureModule.aPollResponse response;
386 if (responses.TryGetValue(key, out response)) 415 if (responses.TryGetValue(key, out response))
387 { 416 {
417 // This is any error response
418 if (response.bytes == 0)
419 return true;
388 420
389 // Normal 421 // Normal
390 if (BytesSent + response.bytes <= ThrottleBytes) 422 if (BytesSent + response.bytes <= ThrottleBytes)
@@ -411,12 +443,12 @@ namespace OpenSim.Region.ClientStack.Linden
411 443
412 return haskey; 444 return haskey;
413 } 445 }
446
414 public void ProcessTime() 447 public void ProcessTime()
415 { 448 {
416 PassTime(); 449 PassTime();
417 } 450 }
418 451
419
420 private void PassTime() 452 private void PassTime()
421 { 453 {
422 currenttime = Util.EnvironmentTickCount(); 454 currenttime = Util.EnvironmentTickCount();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 60c1814..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -57,7 +57,6 @@ namespace OpenSim.Region.ClientStack.Linden
57 public bool Enabled { get; private set; } 57 public bool Enabled { get; private set; }
58 58
59 private Scene m_scene; 59 private Scene m_scene;
60 private UUID m_agentID;
61 60
62 #region ISharedRegionModule Members 61 #region ISharedRegionModule Members
63 62
@@ -118,13 +117,14 @@ namespace OpenSim.Region.ClientStack.Linden
118 public void RegisterCaps(UUID agentID, Caps caps) 117 public void RegisterCaps(UUID agentID, Caps caps)
119 { 118 {
120 IRequestHandler reqHandler 119 IRequestHandler reqHandler
121 = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag, "MeshUploadFlag", agentID.ToString()); 120 = new RestHTTPHandler(
121 "GET", "/CAPS/" + UUID.Random(), ht => MeshUploadFlag(ht, agentID), "MeshUploadFlag", agentID.ToString());
122 122
123 caps.RegisterHandler("MeshUploadFlag", reqHandler); 123 caps.RegisterHandler("MeshUploadFlag", reqHandler);
124 m_agentID = agentID; 124
125 } 125 }
126 126
127 private Hashtable MeshUploadFlag(Hashtable mDhttpMethod) 127 private Hashtable MeshUploadFlag(Hashtable mDhttpMethod, UUID agentID)
128 { 128 {
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
index 060a61c..595d01a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index fcac182..79d56c4 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -56,8 +56,8 @@ namespace OpenSim.Region.ClientStack.Linden
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")] 56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")]
57 public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole 57 public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole
58 { 58 {
59 private static readonly ILog m_log = 59// private static readonly ILog m_log =
60 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 61
62 private Scene m_scene; 62 private Scene m_scene;
63 private IEventQueue m_eventQueue; 63 private IEventQueue m_eventQueue;
@@ -164,8 +164,8 @@ namespace OpenSim.Region.ClientStack.Linden
164 164
165 public class ConsoleHandler : BaseStreamHandler 165 public class ConsoleHandler : BaseStreamHandler
166 { 166 {
167 private static readonly ILog m_log = 167// private static readonly ILog m_log =
168 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 168// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
169 169
170 private RegionConsoleModule m_consoleModule; 170 private RegionConsoleModule m_consoleModule;
171 private UUID m_agentID; 171 private UUID m_agentID;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index 191bccf..7d9f935 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden
59// private static readonly ILog m_log = 59// private static readonly ILog m_log =
60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 61
62 public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
63
62 private Scene m_scene; 64 private Scene m_scene;
63 65
64 /// <summary> 66 /// <summary>
@@ -68,6 +70,7 @@ namespace OpenSim.Region.ClientStack.Linden
68 70
69 private string m_MapImageServerURL = string.Empty; 71 private string m_MapImageServerURL = string.Empty;
70 private string m_SearchURL = string.Empty; 72 private string m_SearchURL = string.Empty;
73 private bool m_ExportSupported = false;
71 74
72 #region ISharedRegionModule Members 75 #region ISharedRegionModule Members
73 76
@@ -85,6 +88,8 @@ namespace OpenSim.Region.ClientStack.Linden
85 } 88 }
86 89
87 m_SearchURL = config.GetString("SearchServerURI", string.Empty); 90 m_SearchURL = config.GetString("SearchServerURI", string.Empty);
91
92 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
88 } 93 }
89 94
90 AddDefaultFeatures(); 95 AddDefaultFeatures();
@@ -94,6 +99,8 @@ namespace OpenSim.Region.ClientStack.Linden
94 { 99 {
95 m_scene = s; 100 m_scene = s;
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 101 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
102
103 m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this);
97 } 104 }
98 105
99 public void RemoveRegion(Scene s) 106 public void RemoveRegion(Scene s)
@@ -148,6 +155,9 @@ namespace OpenSim.Region.ClientStack.Linden
148 if (m_SearchURL != string.Empty) 155 if (m_SearchURL != string.Empty)
149 gridServicesMap["search"] = m_SearchURL; 156 gridServicesMap["search"] = m_SearchURL;
150 m_features["GridServices"] = gridServicesMap; 157 m_features["GridServices"] = gridServicesMap;
158
159 if (m_ExportSupported)
160 m_features["ExportSupported"] = true;
151 } 161 }
152 } 162 }
153 163
@@ -156,7 +166,7 @@ namespace OpenSim.Region.ClientStack.Linden
156 IRequestHandler reqHandler 166 IRequestHandler reqHandler
157 = new RestHTTPHandler( 167 = new RestHTTPHandler(
158 "GET", "/CAPS/" + UUID.Random(), 168 "GET", "/CAPS/" + UUID.Random(),
159 HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); 169 x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString());
160 170
161 caps.RegisterHandler("SimulatorFeatures", reqHandler); 171 caps.RegisterHandler("SimulatorFeatures", reqHandler);
162 } 172 }
@@ -185,18 +195,33 @@ namespace OpenSim.Region.ClientStack.Linden
185 return new OSDMap(m_features); 195 return new OSDMap(m_features);
186 } 196 }
187 197
188 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) 198 private OSDMap DeepCopy()
199 {
200 // This isn't the cheapest way of doing this but the rate
201 // of occurrence is low (on sim entry only) and it's a sure
202 // way to get a true deep copy.
203 OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features));
204
205 return (OSDMap)copy;
206 }
207
208 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID)
189 { 209 {
190// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); 210// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
191 211
212 OSDMap copy = DeepCopy();
213
214 SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest;
215 if (handlerOnSimulatorFeaturesRequest != null)
216 handlerOnSimulatorFeaturesRequest(agentID, ref copy);
217
192 //Send back data 218 //Send back data
193 Hashtable responsedata = new Hashtable(); 219 Hashtable responsedata = new Hashtable();
194 responsedata["int_response_code"] = 200; 220 responsedata["int_response_code"] = 200;
195 responsedata["content_type"] = "text/plain"; 221 responsedata["content_type"] = "text/plain";
196 responsedata["keepalive"] = false; 222 responsedata["keepalive"] = false;
197 223
198 lock (m_features) 224 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy);
199 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features);
200 225
201 return responsedata; 226 return responsedata;
202 } 227 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 6bed95f..eca576d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -190,8 +190,15 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 { 192 {
193 cacheItems[i].TextureID = 193 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
194 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; 194 if (face == null)
195 {
196 textureEntry.CreateFace(cacheItems[i].TextureIndex);
197 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue;
200 }
201 cacheItems[i].TextureID =face.TextureID;
195 if (m_scene.AssetService != null) 202 if (m_scene.AssetService != null)
196 cacheItems[i].TextureAsset = 203 cacheItems[i].TextureAsset =
197 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); 204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
@@ -213,8 +220,16 @@ namespace OpenSim.Region.ClientStack.Linden
213 { 220 {
214 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
215 { 222 {
223 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
224 if (face == null)
225 {
226 textureEntry.CreateFace(cacheItems[i].TextureIndex);
227 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
228 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
229 continue;
230 }
216 cacheItems[i].TextureID = 231 cacheItems[i].TextureID =
217 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID; 232 face.TextureID;
218 } 233 }
219 else 234 else
220 { 235 {
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 04cd474..707cc93 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -39,10 +39,13 @@ using OpenSim.Framework.Servers;
39using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Framework.Capabilities;
42using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
44using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring; 46using OpenSim.Framework.Monitoring;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
46 49
47namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
48{ 51{
@@ -52,11 +55,13 @@ namespace OpenSim.Region.ClientStack.Linden
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
53 public class WebFetchInvDescModule : INonSharedRegionModule 56 public class WebFetchInvDescModule : INonSharedRegionModule
54 { 57 {
55 struct aPollRequest 58 class aPollRequest
56 { 59 {
57 public PollServiceInventoryEventArgs thepoll; 60 public PollServiceInventoryEventArgs thepoll;
58 public UUID reqID; 61 public UUID reqID;
59 public Hashtable request; 62 public Hashtable request;
63 public ScenePresence presence;
64 public List<UUID> folders;
60 } 65 }
61 66
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -71,8 +76,8 @@ namespace OpenSim.Region.ClientStack.Linden
71 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); 76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
72 private static Thread[] m_workerThreads = null; 77 private static Thread[] m_workerThreads = null;
73 78
74 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = 79 private static DoubleQueue<aPollRequest> m_queue =
75 new OpenMetaverse.BlockingQueue<aPollRequest>(); 80 new DoubleQueue<aPollRequest>();
76 81
77 #region ISharedRegionModule Members 82 #region ISharedRegionModule Members
78 83
@@ -143,12 +148,18 @@ namespace OpenSim.Region.ClientStack.Linden
143 148
144 private class PollServiceInventoryEventArgs : PollServiceEventArgs 149 private class PollServiceInventoryEventArgs : PollServiceEventArgs
145 { 150 {
151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
152
146 private Dictionary<UUID, Hashtable> responses = 153 private Dictionary<UUID, Hashtable> responses =
147 new Dictionary<UUID, Hashtable>(); 154 new Dictionary<UUID, Hashtable>();
148 155
149 public PollServiceInventoryEventArgs(UUID pId) : 156 private Scene m_scene;
157
158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) :
150 base(null, null, null, null, pId, int.MaxValue) 159 base(null, null, null, null, pId, int.MaxValue)
151 { 160 {
161 m_scene = scene;
162
152 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; 163 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
153 GetEvents = (x, y) => 164 GetEvents = (x, y) =>
154 { 165 {
@@ -167,12 +178,68 @@ namespace OpenSim.Region.ClientStack.Linden
167 178
168 Request = (x, y) => 179 Request = (x, y) =>
169 { 180 {
181 ScenePresence sp = m_scene.GetScenePresence(Id);
182 if (sp == null)
183 {
184 m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id);
185 return;
186 }
187
170 aPollRequest reqinfo = new aPollRequest(); 188 aPollRequest reqinfo = new aPollRequest();
171 reqinfo.thepoll = this; 189 reqinfo.thepoll = this;
172 reqinfo.reqID = x; 190 reqinfo.reqID = x;
173 reqinfo.request = y; 191 reqinfo.request = y;
192 reqinfo.presence = sp;
193 reqinfo.folders = new List<UUID>();
194
195 // Decode the request here
196 string request = y["body"].ToString();
197
198 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
199
200 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
201 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
202
203 Hashtable hash = new Hashtable();
204 try
205 {
206 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
207 }
208 catch (LLSD.LLSDParseException e)
209 {
210 m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
211 m_log.Error("Request: " + request);
212 return;
213 }
214 catch (System.Xml.XmlException)
215 {
216 m_log.ErrorFormat("[INVENTORY]: XML Format error");
217 }
218
219 ArrayList foldersrequested = (ArrayList)hash["folders"];
220
221 bool highPriority = false;
222
223 for (int i = 0; i < foldersrequested.Count; i++)
224 {
225 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
226 string folder = inventoryhash["folder_id"].ToString();
227 UUID folderID;
228 if (UUID.TryParse(folder, out folderID))
229 {
230 if (!reqinfo.folders.Contains(folderID))
231 {
232 if (sp.COF != UUID.Zero && sp.COF == folderID)
233 highPriority = true;
234 reqinfo.folders.Add(folderID);
235 }
236 }
237 }
174 238
175 m_queue.Enqueue(reqinfo); 239 if (highPriority)
240 m_queue.EnqueueHigh(reqinfo);
241 else
242 m_queue.EnqueueLow(reqinfo);
176 }; 243 };
177 244
178 NoEvents = (x, y) => 245 NoEvents = (x, y) =>
@@ -208,7 +275,7 @@ namespace OpenSim.Region.ClientStack.Linden
208 response["reusecontext"] = false; 275 response["reusecontext"] = false;
209 276
210 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( 277 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
211 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); 278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
212 279
213 lock (responses) 280 lock (responses)
214 responses[requestID] = response; 281 responses[requestID] = response;
@@ -220,7 +287,7 @@ namespace OpenSim.Region.ClientStack.Linden
220 string capUrl = "/CAPS/" + UUID.Random() + "/"; 287 string capUrl = "/CAPS/" + UUID.Random() + "/";
221 288
222 // Register this as a poll service 289 // Register this as a poll service
223 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID); 290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
224 291
225 args.Type = PollServiceEventArgs.EventType.Inventory; 292 args.Type = PollServiceEventArgs.EventType.Inventory;
226 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index fd82db7..98160c9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -51,6 +51,7 @@ using RegionFlags = OpenMetaverse.RegionFlags;
51using Nini.Config; 51using Nini.Config;
52 52
53using System.IO; 53using System.IO;
54using PermissionMask = OpenSim.Framework.PermissionMask;
54 55
55namespace OpenSim.Region.ClientStack.LindenUDP 56namespace OpenSim.Region.ClientStack.LindenUDP
56{ 57{
@@ -822,6 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
822 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 823 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
823 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 824 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
824 825
826 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0];
825// OutPacket(handshake, ThrottleOutPacketType.Task); 827// OutPacket(handshake, ThrottleOutPacketType.Task);
826 // use same as MoveAgentIntoRegion (both should be task ) 828 // use same as MoveAgentIntoRegion (both should be task )
827 OutPacket(handshake, ThrottleOutPacketType.Unknown); 829 OutPacket(handshake, ThrottleOutPacketType.Unknown);
@@ -901,9 +903,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
901 } 903 }
902 } 904 }
903 905
904 public void SendGenericMessage(string method, List<string> message) 906 public void SendGenericMessage(string method, UUID invoice, List<string> message)
905 { 907 {
906 GenericMessagePacket gmp = new GenericMessagePacket(); 908 GenericMessagePacket gmp = new GenericMessagePacket();
909
910 gmp.AgentData.AgentID = AgentId;
911 gmp.AgentData.SessionID = m_sessionId;
912 gmp.AgentData.TransactionID = invoice;
913
907 gmp.MethodData.Method = Util.StringToBytes256(method); 914 gmp.MethodData.Method = Util.StringToBytes256(method);
908 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 915 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
909 int i = 0; 916 int i = 0;
@@ -916,9 +923,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
916 OutPacket(gmp, ThrottleOutPacketType.Task); 923 OutPacket(gmp, ThrottleOutPacketType.Task);
917 } 924 }
918 925
919 public void SendGenericMessage(string method, List<byte[]> message) 926 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
920 { 927 {
921 GenericMessagePacket gmp = new GenericMessagePacket(); 928 GenericMessagePacket gmp = new GenericMessagePacket();
929
930 gmp.AgentData.AgentID = AgentId;
931 gmp.AgentData.SessionID = m_sessionId;
932 gmp.AgentData.TransactionID = invoice;
933
922 gmp.MethodData.Method = Util.StringToBytes256(method); 934 gmp.MethodData.Method = Util.StringToBytes256(method);
923 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 935 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
924 int i = 0; 936 int i = 0;
@@ -1801,7 +1813,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1801 1813
1802 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) 1814 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item)
1803 { 1815 {
1804 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 1816 // Fudge this value. It's only needed to make the CRC anyway
1817 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
1805 1818
1806 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); 1819 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply);
1807 // TODO: don't create new blocks if recycling an old packet 1820 // TODO: don't create new blocks if recycling an old packet
@@ -2006,7 +2019,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2006 2019
2007 protected void SendBulkUpdateInventoryItem(InventoryItemBase item) 2020 protected void SendBulkUpdateInventoryItem(InventoryItemBase item)
2008 { 2021 {
2009 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2022 const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff;
2010 2023
2011 BulkUpdateInventoryPacket bulkUpdate 2024 BulkUpdateInventoryPacket bulkUpdate
2012 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); 2025 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
@@ -2065,7 +2078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2065 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> 2078 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2066 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) 2079 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2067 { 2080 {
2068 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2081 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2069 2082
2070 UpdateCreateInventoryItemPacket InventoryReply 2083 UpdateCreateInventoryItemPacket InventoryReply
2071 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket( 2084 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(
@@ -2654,7 +2667,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2654 byte physshapetype = part.PhysicsShapeType; 2667 byte physshapetype = part.PhysicsShapeType;
2655 float density = part.Density; 2668 float density = part.Density;
2656 float friction = part.Friction; 2669 float friction = part.Friction;
2657 float bounce = part.Bounciness; 2670 float bounce = part.Restitution;
2658 float gravmod = part.GravityModifier; 2671 float gravmod = part.GravityModifier;
2659 2672
2660 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2673 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
@@ -3604,7 +3617,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3604 3617
3605 avp.Sender.IsTrial = false; 3618 avp.Sender.IsTrial = false;
3606 avp.Sender.ID = agentID; 3619 avp.Sender.ID = agentID;
3607 m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3620 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3621 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3608 OutPacket(avp, ThrottleOutPacketType.Task); 3622 OutPacket(avp, ThrottleOutPacketType.Task);
3609 } 3623 }
3610 3624
@@ -3892,6 +3906,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3892 { 3906 {
3893 part.Shape.LightEntry = false; 3907 part.Shape.LightEntry = false;
3894 } 3908 }
3909
3910 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3911 {
3912 // Ensure that mesh has at least 8 valid faces
3913 part.Shape.ProfileBegin = 12500;
3914 part.Shape.ProfileEnd = 0;
3915 part.Shape.ProfileHollow = 27500;
3916 }
3917 }
3918
3919 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3920 {
3921 // Ensure that mesh has at least 8 valid faces
3922 part.Shape.ProfileBegin = 12500;
3923 part.Shape.ProfileEnd = 0;
3924 part.Shape.ProfileHollow = 27500;
3895 } 3925 }
3896 } 3926 }
3897 3927
@@ -4208,7 +4238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4208 pack.Stat = stats.StatsBlock; 4238 pack.Stat = stats.StatsBlock;
4209 4239
4210 pack.Header.Reliable = false; 4240 pack.Header.Reliable = false;
4211 4241 pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0];
4212 OutPacket(pack, ThrottleOutPacketType.Task); 4242 OutPacket(pack, ThrottleOutPacketType.Task);
4213 } 4243 }
4214 4244
@@ -4599,7 +4629,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4599 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); 4629 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
4600 rinfopack.AgentData.AgentID = AgentId; 4630 rinfopack.AgentData.AgentID = AgentId;
4601 rinfopack.AgentData.SessionID = SessionId; 4631 rinfopack.AgentData.SessionID = SessionId;
4602 4632 rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
4603 4633
4604 OutPacket(rinfopack, ThrottleOutPacketType.Task); 4634 OutPacket(rinfopack, ThrottleOutPacketType.Task);
4605 } 4635 }
@@ -4952,6 +4982,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4952 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; 4982 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4953 rotation = part.RotationOffset * presence.Rotation; 4983 rotation = part.RotationOffset * presence.Rotation;
4954 } 4984 }
4985 angularVelocity = Vector3.Zero;
4986 }
4987 else
4988 {
4989 angularVelocity = presence.AngularVelocity;
4990 rotation = presence.Rotation;
4955 } 4991 }
4956 4992
4957 attachPoint = 0; 4993 attachPoint = 0;
@@ -4963,9 +4999,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4963 // in that direction, even though we don't model this on the server. Implementing this in the future 4999 // in that direction, even though we don't model this on the server. Implementing this in the future
4964 // may improve movement smoothness. 5000 // may improve movement smoothness.
4965// acceleration = new Vector3(1, 0, 0); 5001// acceleration = new Vector3(1, 0, 0);
4966 5002
4967 angularVelocity = Vector3.Zero;
4968
4969 if (sendTexture) 5003 if (sendTexture)
4970 textureEntry = presence.Appearance.Texture.GetBytes(); 5004 textureEntry = presence.Appearance.Texture.GetBytes();
4971 else 5005 else
@@ -6575,19 +6609,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6575 #endregion 6609 #endregion
6576 6610
6577 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6611 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6578 if (handlerAgentRequestSit != null)
6579 if (!(agentRequestSit.AgentData == null
6580 || agentRequestSit.TargetObject == null
6581 || agentRequestSit.TargetObject.TargetID == null
6582 || agentRequestSit.TargetObject.Offset == null))
6583 {
6584 var sp = m_scene.GetScenePresence(agentRequestSit.AgentData.AgentID);
6585 if (sp == null || sp.ParentID != 0) // ignore packet if agent is already sitting
6586 return true;
6587 6612
6588 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, 6613 if (handlerAgentRequestSit != null)
6589 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); 6614 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
6590 } 6615 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
6591 } 6616 }
6592 return true; 6617 return true;
6593 } 6618 }
@@ -7193,7 +7218,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7193 7218
7194 if (handlerUpdatePrimFlags != null) 7219 if (handlerUpdatePrimFlags != null)
7195 { 7220 {
7196 byte[] data = Pack.ToBytes(); 7221// byte[] data = Pack.ToBytes();
7197 // 46,47,48 are special positions within the packet 7222 // 46,47,48 are special positions within the packet
7198 // This may change so perhaps we need a better way 7223 // This may change so perhaps we need a better way
7199 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) 7224 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
@@ -9835,7 +9860,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9835 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; 9860 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest;
9836 if (handlerEconomoyDataRequest != null) 9861 if (handlerEconomoyDataRequest != null)
9837 { 9862 {
9838 handlerEconomoyDataRequest(AgentId); 9863 handlerEconomoyDataRequest(this);
9839 } 9864 }
9840 return true; 9865 return true;
9841 } 9866 }
@@ -12242,11 +12267,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12242 if (logPacket) 12267 if (logPacket)
12243 m_log.DebugFormat( 12268 m_log.DebugFormat(
12244 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", 12269 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
12245 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); 12270 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
12246 } 12271 }
12247 12272
12248 if (!ProcessPacketMethod(packet)) 12273 if (!ProcessPacketMethod(packet))
12249 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 12274 m_log.WarnFormat(
12275 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
12276 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
12250 } 12277 }
12251 12278
12252 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 12279 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -12454,6 +12481,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12454 return String.Empty; 12481 return String.Empty;
12455 } 12482 }
12456 12483
12484 public OSDMap OReport(string uptime, string version)
12485 {
12486 return new OSDMap();
12487 }
12488
12457 /// <summary> 12489 /// <summary>
12458 /// Make an asset request to the asset service in response to a client request. 12490 /// Make an asset request to the asset service in response to a client request.
12459 /// </summary> 12491 /// </summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index da1ccb3..4154ef2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -281,25 +281,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
281 m_shouldCollectStats = false; 281 m_shouldCollectStats = false;
282 if (config != null) 282 if (config != null)
283 { 283 {
284 if (config.Contains("enabled") && config.GetBoolean("enabled")) 284 m_shouldCollectStats = config.GetBoolean("Enabled", false);
285 { 285 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
286 if (config.Contains("collect_packet_headers")) 286 binStatsDir = config.GetString("stats_dir", ".");
287 m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); 287 m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
288 if (config.Contains("packet_headers_period_seconds")) 288 }
289 { 289 #endregion BinaryStats
290 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds"));
291 }
292 if (config.Contains("stats_dir"))
293 {
294 binStatsDir = config.GetString("stats_dir");
295 }
296 }
297 else
298 {
299 m_shouldCollectStats = false;
300 }
301 }
302 #endregion BinaryStats
303 290
304 m_throttle = new TokenBucket(null, sceneThrottleBps); 291 m_throttle = new TokenBucket(null, sceneThrottleBps);
305 ThrottleRates = new ThrottleRates(configSource); 292 ThrottleRates = new ThrottleRates(configSource);
@@ -1309,8 +1296,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1309 static object binStatsLogLock = new object(); 1296 static object binStatsLogLock = new object();
1310 static string binStatsDir = ""; 1297 static string binStatsDir = "";
1311 1298
1299 //for Aggregated In/Out BW logging
1300 static bool m_aggregatedBWStats = false;
1301 static long m_aggregatedBytesIn = 0;
1302 static long m_aggregatedByestOut = 0;
1303 static object aggBWStatsLock = new object();
1304
1305 public static long AggregatedLLUDPBytesIn
1306 {
1307 get { return m_aggregatedBytesIn; }
1308 }
1309 public static long AggregatedLLUDPBytesOut
1310 {
1311 get {return m_aggregatedByestOut;}
1312 }
1313
1312 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) 1314 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1313 { 1315 {
1316 if (m_aggregatedBWStats)
1317 {
1318 lock (aggBWStatsLock)
1319 {
1320 if (incoming)
1321 m_aggregatedBytesIn += size;
1322 else
1323 m_aggregatedByestOut += size;
1324 }
1325 }
1326
1314 if (!m_shouldCollectStats) return; 1327 if (!m_shouldCollectStats) return;
1315 1328
1316 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size 1329 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
@@ -1903,112 +1916,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1903 } 1916 }
1904 } 1917 }
1905 } 1918 }
1906
1907 internal class DoubleQueue<T> where T:class
1908 {
1909 private Queue<T> m_lowQueue = new Queue<T>();
1910 private Queue<T> m_highQueue = new Queue<T>();
1911
1912 private object m_syncRoot = new object();
1913 private Semaphore m_s = new Semaphore(0, 1);
1914
1915 public DoubleQueue()
1916 {
1917 }
1918
1919 public virtual int Count
1920 {
1921 get { return m_highQueue.Count + m_lowQueue.Count; }
1922 }
1923
1924 public virtual void Enqueue(T data)
1925 {
1926 Enqueue(m_lowQueue, data);
1927 }
1928
1929 public virtual void EnqueueLow(T data)
1930 {
1931 Enqueue(m_lowQueue, data);
1932 }
1933
1934 public virtual void EnqueueHigh(T data)
1935 {
1936 Enqueue(m_highQueue, data);
1937 }
1938
1939 private void Enqueue(Queue<T> q, T data)
1940 {
1941 lock (m_syncRoot)
1942 {
1943 m_lowQueue.Enqueue(data);
1944 m_s.WaitOne(0);
1945 m_s.Release();
1946 }
1947 }
1948
1949 public virtual T Dequeue()
1950 {
1951 return Dequeue(Timeout.Infinite);
1952 }
1953
1954 public virtual T Dequeue(int tmo)
1955 {
1956 return Dequeue(TimeSpan.FromMilliseconds(tmo));
1957 }
1958
1959 public virtual T Dequeue(TimeSpan wait)
1960 {
1961 T res = null;
1962
1963 if (!Dequeue(wait, ref res))
1964 return null;
1965
1966 return res;
1967 }
1968
1969 public bool Dequeue(int timeout, ref T res)
1970 {
1971 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
1972 }
1973
1974 public bool Dequeue(TimeSpan wait, ref T res)
1975 {
1976 if (!m_s.WaitOne(wait))
1977 return false;
1978
1979 lock (m_syncRoot)
1980 {
1981 if (m_highQueue.Count > 0)
1982 res = m_highQueue.Dequeue();
1983 else
1984 res = m_lowQueue.Dequeue();
1985
1986 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
1987 return true;
1988
1989 try
1990 {
1991 m_s.Release();
1992 }
1993 catch
1994 {
1995 }
1996
1997 return true;
1998 }
1999 }
2000
2001 public virtual void Clear()
2002 {
2003
2004 lock (m_syncRoot)
2005 {
2006 // Make sure sem count is 0
2007 m_s.WaitOne(0);
2008
2009 m_lowQueue.Clear();
2010 m_highQueue.Clear();
2011 }
2012 }
2013 }
2014} 1919}
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/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index af2f6f8..98ef72f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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/ClientStack/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
index e72bd86..0b6ee2f 100644
--- a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
index 7332415..f489262 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
42 public class AssetTransactionModule : INonSharedRegionModule, 42 public class AssetTransactionModule : INonSharedRegionModule,
43 IAgentAssetTransactions 43 IAgentAssetTransactions
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 protected Scene m_Scene; 47 protected Scene m_Scene;
48 private bool m_dumpAssetsToFile = false; 48 private bool m_dumpAssetsToFile = false;
@@ -214,9 +214,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
214 public void HandleTaskItemUpdateFromTransaction( 214 public void HandleTaskItemUpdateFromTransaction(
215 IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) 215 IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
216 { 216 {
217 m_log.DebugFormat( 217// m_log.DebugFormat(
218 "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", 218// "[ASSET TRANSACTION MODULE]: Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
219 item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); 219// item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
220 220
221 AgentAssetTransactions transactions = 221 AgentAssetTransactions transactions =
222 GetUserTransactions(remoteClient.AgentId); 222 GetUserTransactions(remoteClient.AgentId);
@@ -230,15 +230,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
230 /// </summary> 230 /// </summary>
231 /// <param name="remoteClient"></param> 231 /// <param name="remoteClient"></param>
232 /// <param name="assetID"></param> 232 /// <param name="assetID"></param>
233 /// <param name="transaction"></param> 233 /// <param name="transactionID"></param>
234 /// <param name="type"></param> 234 /// <param name="type"></param>
235 /// <param name="data"></param></param> 235 /// <param name="data"></param></param>
236 /// <param name="tempFile"></param> 236 /// <param name="tempFile"></param>
237 public void HandleUDPUploadRequest(IClientAPI remoteClient, 237 public void HandleUDPUploadRequest(IClientAPI remoteClient,
238 UUID assetID, UUID transaction, sbyte type, byte[] data, 238 UUID assetID, UUID transactionID, sbyte type, byte[] data,
239 bool storeLocal, bool tempFile) 239 bool storeLocal, bool tempFile)
240 { 240 {
241// m_log.Debug("HandleUDPUploadRequest - assetID: " + assetID.ToString() + " transaction: " + transaction.ToString() + " type: " + type.ToString() + " storelocal: " + storeLocal + " tempFile: " + tempFile); 241// m_log.DebugFormat(
242// "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}",
243// assetID, transactionID, type, storeLocal, tempFile, data.Length);
242 244
243 if (((AssetType)type == AssetType.Texture || 245 if (((AssetType)type == AssetType.Texture ||
244 (AssetType)type == AssetType.Sound || 246 (AssetType)type == AssetType.Sound ||
@@ -274,8 +276,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
274 } 276 }
275 277
276 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); 278 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
277 AssetXferUploader uploader = transactions.RequestXferUploader(transaction); 279 AssetXferUploader uploader = transactions.RequestXferUploader(transactionID);
278 uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile); 280 uploader.StartUpload(remoteClient, assetID, transactionID, type, data, storeLocal, tempFile);
279 } 281 }
280 282
281 /// <summary> 283 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index 0aa4693..ffff37d 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
@@ -34,6 +34,7 @@ using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
37using PermissionMask = OpenSim.Framework.PermissionMask;
37 38
38namespace OpenSim.Region.CoreModules.Agent.AssetTransaction 39namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
39{ 40{
@@ -260,10 +261,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
260 { 261 {
261 CompleteTaskItemUpdate(m_updateTaskItemData); 262 CompleteTaskItemUpdate(m_updateTaskItemData);
262 } 263 }
263// else if (m_storeLocal) 264 else if (m_asset.Local)
264// { 265 {
265// m_Scene.AssetService.Store(m_asset); 266 m_Scene.AssetService.Store(m_asset);
266// } 267 }
267 } 268 }
268 269
269 m_log.DebugFormat( 270 m_log.DebugFormat(
@@ -339,7 +340,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
339 // to avoid a race condition when the appearance module retrieves the item to set the asset id in 340 // to avoid a race condition when the appearance module retrieves the item to set the asset id in
340 // the AvatarAppearance structure. 341 // the AvatarAppearance structure.
341 item.AssetID = m_asset.FullID; 342 item.AssetID = m_asset.FullID;
342 m_Scene.InventoryService.UpdateItem(item); 343 if (item.AssetID != UUID.Zero)
344 m_Scene.InventoryService.UpdateItem(item);
343 345
344 if (m_uploadState == UploadState.Complete) 346 if (m_uploadState == UploadState.Complete)
345 { 347 {
@@ -390,6 +392,11 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
390// m_asset.FullID, item.Name, ourClient.Name); 392// m_asset.FullID, item.Name, ourClient.Name);
391 393
392 m_Scene.AssetService.Store(m_asset); 394 m_Scene.AssetService.Store(m_asset);
395 if (m_asset.FullID != UUID.Zero)
396 {
397 item.AssetID = m_asset.FullID;
398 m_Scene.InventoryService.UpdateItem(item);
399 }
393 400
394 m_transactions.RemoveXferUploader(m_transactionID); 401 m_transactions.RemoveXferUploader(m_transactionID);
395 } 402 }
@@ -424,8 +431,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
424 item.AssetType = type; 431 item.AssetType = type;
425 item.InvType = invType; 432 item.InvType = invType;
426 item.Folder = InventFolder; 433 item.Folder = InventFolder;
427 item.BasePermissions = 0x7fffffff; 434 item.BasePermissions = (uint)(PermissionMask.All | PermissionMask.Export);
428 item.CurrentPermissions = 0x7fffffff; 435 item.CurrentPermissions = item.BasePermissions;
429 item.GroupPermissions=0; 436 item.GroupPermissions=0;
430 item.EveryOnePermissions=0; 437 item.EveryOnePermissions=0;
431 item.NextPermissions = nextPerm; 438 item.NextPermissions = nextPerm;
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index a0f1e8c..d510d82 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -363,12 +363,37 @@ namespace OpenSim.Region.CoreModules.Asset
363 /// Try to get an asset from the file cache. 363 /// Try to get an asset from the file cache.
364 /// </summary> 364 /// </summary>
365 /// <param name="id"></param> 365 /// <param name="id"></param>
366 /// <returns></returns> 366 /// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns>
367 private AssetBase GetFromFileCache(string id) 367 private AssetBase GetFromFileCache(string id)
368 { 368 {
369 string filename = GetFileName(id);
370
371#if WAIT_ON_INPROGRESS_REQUESTS
372 // Check if we're already downloading this asset. If so, try to wait for it to
373 // download.
374 if (m_WaitOnInprogressTimeout > 0)
375 {
376 m_RequestsForInprogress++;
377
378 ManualResetEvent waitEvent;
379 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
380 {
381 waitEvent.WaitOne(m_WaitOnInprogressTimeout);
382 return Get(id);
383 }
384 }
385#else
386 // Track how often we have the problem that an asset is requested while
387 // it is still being downloaded by a previous request.
388 if (m_CurrentlyWriting.Contains(filename))
389 {
390 m_RequestsForInprogress++;
391 return null;
392 }
393#endif
394
369 AssetBase asset = null; 395 AssetBase asset = null;
370 396
371 string filename = GetFileName(id);
372 if (File.Exists(filename)) 397 if (File.Exists(filename))
373 { 398 {
374 FileStream stream = null; 399 FileStream stream = null;
@@ -383,7 +408,7 @@ namespace OpenSim.Region.CoreModules.Asset
383 } 408 }
384 catch (System.Runtime.Serialization.SerializationException e) 409 catch (System.Runtime.Serialization.SerializationException e)
385 { 410 {
386 m_log.ErrorFormat( 411 m_log.WarnFormat(
387 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", 412 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
388 filename, id, e.Message, e.StackTrace); 413 filename, id, e.Message, e.StackTrace);
389 414
@@ -395,9 +420,10 @@ namespace OpenSim.Region.CoreModules.Asset
395 } 420 }
396 catch (Exception e) 421 catch (Exception e)
397 { 422 {
398 m_log.ErrorFormat( 423 m_log.WarnFormat(
399 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", 424 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
400 filename, id, e.Message, e.StackTrace); 425 filename, id, e.Message, e.StackTrace);
426
401 } 427 }
402 finally 428 finally
403 { 429 {
@@ -406,28 +432,6 @@ namespace OpenSim.Region.CoreModules.Asset
406 } 432 }
407 } 433 }
408 434
409#if WAIT_ON_INPROGRESS_REQUESTS
410 // Check if we're already downloading this asset. If so, try to wait for it to
411 // download.
412 if (m_WaitOnInprogressTimeout > 0)
413 {
414 m_RequestsForInprogress++;
415
416 ManualResetEvent waitEvent;
417 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
418 {
419 waitEvent.WaitOne(m_WaitOnInprogressTimeout);
420 return Get(id);
421 }
422 }
423#else
424 // Track how often we have the problem that an asset is requested while
425 // it is still being downloaded by a previous request.
426 if (m_CurrentlyWriting.Contains(filename))
427 {
428 m_RequestsForInprogress++;
429 }
430#endif
431 return asset; 435 return asset;
432 } 436 }
433 437
@@ -552,7 +556,7 @@ namespace OpenSim.Region.CoreModules.Asset
552 } 556 }
553 catch (Exception e) 557 catch (Exception e)
554 { 558 {
555 m_log.ErrorFormat( 559 m_log.WarnFormat(
556 "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", 560 "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}",
557 id, e.Message, e.StackTrace); 561 id, e.Message, e.StackTrace);
558 } 562 }
@@ -603,29 +607,39 @@ namespace OpenSim.Region.CoreModules.Asset
603 /// <param name="purgeLine"></param> 607 /// <param name="purgeLine"></param>
604 private void CleanExpiredFiles(string dir, DateTime purgeLine) 608 private void CleanExpiredFiles(string dir, DateTime purgeLine)
605 { 609 {
606 foreach (string file in Directory.GetFiles(dir)) 610 try
607 { 611 {
608 if (File.GetLastAccessTime(file) < purgeLine) 612 foreach (string file in Directory.GetFiles(dir))
609 { 613 {
610 File.Delete(file); 614 if (File.GetLastAccessTime(file) < purgeLine)
615 {
616 File.Delete(file);
617 }
611 } 618 }
612 }
613 619
614 // Recurse into lower tiers 620 // Recurse into lower tiers
615 foreach (string subdir in Directory.GetDirectories(dir)) 621 foreach (string subdir in Directory.GetDirectories(dir))
616 { 622 {
617 CleanExpiredFiles(subdir, purgeLine); 623 CleanExpiredFiles(subdir, purgeLine);
618 } 624 }
619 625
620 // Check if a tier directory is empty, if so, delete it 626 // Check if a tier directory is empty, if so, delete it
621 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; 627 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
622 if (dirSize == 0) 628 if (dirSize == 0)
623 { 629 {
624 Directory.Delete(dir); 630 Directory.Delete(dir);
631 }
632 else if (dirSize >= m_CacheWarnAt)
633 {
634 m_log.WarnFormat(
635 "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration",
636 dir, dirSize);
637 }
625 } 638 }
626 else if (dirSize >= m_CacheWarnAt) 639 catch (Exception e)
627 { 640 {
628 m_log.WarnFormat("[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize); 641 m_log.Warn(
642 string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e);
629 } 643 }
630 } 644 }
631 645
@@ -684,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Asset
684 } 698 }
685 catch (IOException e) 699 catch (IOException e)
686 { 700 {
687 m_log.ErrorFormat( 701 m_log.WarnFormat(
688 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", 702 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.",
689 asset.ID, tempname, filename, directory, e.Message, e.StackTrace); 703 asset.ID, tempname, filename, directory, e.Message, e.StackTrace);
690 704
@@ -763,17 +777,31 @@ namespace OpenSim.Region.CoreModules.Asset
763 /// <summary> 777 /// <summary>
764 /// This notes the last time the Region had a deep asset scan performed on it. 778 /// This notes the last time the Region had a deep asset scan performed on it.
765 /// </summary> 779 /// </summary>
766 /// <param name="RegionID"></param> 780 /// <param name="regionID"></param>
767 private void StampRegionStatusFile(UUID RegionID) 781 private void StampRegionStatusFile(UUID regionID)
768 { 782 {
769 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac"); 783 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac");
770 if (File.Exists(RegionCacheStatusFile)) 784
785 try
771 { 786 {
772 File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); 787 if (File.Exists(RegionCacheStatusFile))
788 {
789 File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
790 }
791 else
792 {
793 File.WriteAllText(
794 RegionCacheStatusFile,
795 "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
796 }
773 } 797 }
774 else 798 catch (Exception e)
775 { 799 {
776 File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); 800 m_log.Warn(
801 string.Format(
802 "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ",
803 regionID),
804 e);
777 } 805 }
778 } 806 }
779 807
@@ -790,32 +818,43 @@ namespace OpenSim.Region.CoreModules.Asset
790 { 818 {
791 UuidGatherer gatherer = new UuidGatherer(m_AssetService); 819 UuidGatherer gatherer = new UuidGatherer(m_AssetService);
792 820
821 HashSet<UUID> uniqueUuids = new HashSet<UUID>();
793 Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>(); 822 Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>();
823
794 foreach (Scene s in m_Scenes) 824 foreach (Scene s in m_Scenes)
795 { 825 {
796 StampRegionStatusFile(s.RegionInfo.RegionID); 826 StampRegionStatusFile(s.RegionInfo.RegionID);
797 827
798 s.ForEachSOG(delegate(SceneObjectGroup e) 828 s.ForEachSOG(delegate(SceneObjectGroup e)
799 { 829 {
800 gatherer.GatherAssetUuids(e, assets); 830 gatherer.GatherAssetUuids(e, assets);
801 });
802 }
803 831
804 foreach (UUID assetID in assets.Keys) 832 foreach (UUID assetID in assets.Keys)
805 { 833 {
806 string filename = GetFileName(assetID.ToString()); 834 uniqueUuids.Add(assetID);
807 835
808 if (File.Exists(filename)) 836 string filename = GetFileName(assetID.ToString());
809 { 837
810 File.SetLastAccessTime(filename, DateTime.Now); 838 if (File.Exists(filename))
811 } 839 {
812 else if (storeUncached) 840 File.SetLastAccessTime(filename, DateTime.Now);
813 { 841 }
814 m_AssetService.Get(assetID.ToString()); 842 else if (storeUncached)
815 } 843 {
844 AssetBase cachedAsset = m_AssetService.Get(assetID.ToString());
845 if (cachedAsset == null && assets[assetID] != AssetType.Unknown)
846 m_log.DebugFormat(
847 "[FLOTSAM ASSET CACHE]: Could not find asset {0}, type {1} referenced by object {2} at {3} in scene {4} when pre-caching all scene assets",
848 assetID, assets[assetID], e.Name, e.AbsolutePosition, s.Name);
849 }
850 }
851
852 assets.Clear();
853 });
816 } 854 }
817 855
818 return assets.Keys.Count; 856
857 return uniqueUuids.Count;
819 } 858 }
820 859
821 /// <summary> 860 /// <summary>
@@ -831,7 +870,7 @@ namespace OpenSim.Region.CoreModules.Asset
831 } 870 }
832 catch (Exception e) 871 catch (Exception e)
833 { 872 {
834 m_log.ErrorFormat( 873 m_log.WarnFormat(
835 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", 874 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}",
836 dir, m_CacheDirectory, e.Message, e.StackTrace); 875 dir, m_CacheDirectory, e.Message, e.StackTrace);
837 } 876 }
@@ -845,7 +884,7 @@ namespace OpenSim.Region.CoreModules.Asset
845 } 884 }
846 catch (Exception e) 885 catch (Exception e)
847 { 886 {
848 m_log.ErrorFormat( 887 m_log.WarnFormat(
849 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", 888 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}",
850 file, m_CacheDirectory, e.Message, e.StackTrace); 889 file, m_CacheDirectory, e.Message, e.StackTrace);
851 } 890 }
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..cb724aa 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -49,6 +49,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
49 { 49 {
50 #region INonSharedRegionModule 50 #region INonSharedRegionModule
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 public int DebugLevel { get; set; }
52 54
53 private Scene m_scene; 55 private Scene m_scene;
54 private IInventoryAccessModule m_invAccessModule; 56 private IInventoryAccessModule m_invAccessModule;
@@ -76,10 +78,66 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
76 m_scene.RegisterModuleInterface<IAttachmentsModule>(this); 78 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
77 79
78 if (Enabled) 80 if (Enabled)
81 {
79 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 82 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
83 m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true);
84 m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false);
85
86 MainConsole.Instance.Commands.AddCommand(
87 "Debug",
88 false,
89 "debug attachments",
90 "debug attachments [0|1]",
91 "Turn on attachments debugging\n"
92 + " <= 0 - turns off debugging\n"
93 + " >= 1 - turns on attachment message logging\n",
94 HandleDebugAttachments);
95 }
80 96
81 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI 97 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
82 } 98 }
99
100 private void HandleDebugAttachments(string module, string[] args)
101 {
102 int debugLevel;
103
104 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
105 {
106 MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]");
107 }
108 else
109 {
110 DebugLevel = debugLevel;
111 MainConsole.Instance.OutputFormat(
112 "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.Name);
113 }
114 }
115
116 /// <summary>
117 /// Listen for client triggered running state changes so that we can persist the script's object if necessary.
118 /// </summary>
119 /// <param name='localID'></param>
120 /// <param name='itemID'></param>
121 private void HandleScriptStateChange(uint localID, bool started)
122 {
123 SceneObjectGroup sog = m_scene.GetGroupByPrim(localID);
124 if (sog != null && sog.IsAttachment)
125 {
126 if (!started)
127 {
128 // FIXME: This is a convoluted way for working out whether the script state has changed to stop
129 // because it has been manually stopped or because the stop was called in UpdateDetachedObject() below
130 // This needs to be handled in a less tangled way.
131 ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar);
132 if (sp.ControllingClient.IsActive)
133 sog.HasGroupChanged = true;
134 }
135 else
136 {
137 sog.HasGroupChanged = true;
138 }
139 }
140 }
83 141
84 public void RemoveRegion(Scene scene) 142 public void RemoveRegion(Scene scene)
85 { 143 {
@@ -153,10 +211,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
153 } 211 }
154 } 212 }
155 213
156 /// <summary>
157 /// RezAttachments. This should only be called upon login on the first region.
158 /// Attachment rezzings on crossings and TPs are done in a different way.
159 /// </summary>
160 public void RezAttachments(IScenePresence sp) 214 public void RezAttachments(IScenePresence sp)
161 { 215 {
162 if (!Enabled) 216 if (!Enabled)
@@ -165,10 +219,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
165 if (null == sp.Appearance) 219 if (null == sp.Appearance)
166 { 220 {
167 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); 221 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID);
222
168 return; 223 return;
169 } 224 }
170 225
171// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); 226 if (sp.GetAttachments().Count > 0)
227 {
228 if (DebugLevel > 0)
229 m_log.DebugFormat(
230 "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments",
231 m_scene.Name, sp.Name);
232
233 return;
234 }
235
236 if (DebugLevel > 0)
237 m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name);
172 238
173 XmlDocument doc = new XmlDocument(); 239 XmlDocument doc = new XmlDocument();
174 string stateData = String.Empty; 240 string stateData = String.Empty;
@@ -235,10 +301,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
235 301
236 // If we're an NPC then skip all the item checks and manipulations since we don't have an 302 // If we're an NPC then skip all the item checks and manipulations since we don't have an
237 // inventory right now. 303 // inventory right now.
238 if (sp.PresenceType == PresenceType.Npc) 304 RezSingleAttachmentFromInventoryInternal(
239 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null); 305 sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true, null);
240 else
241 RezSingleAttachmentFromInventory(sp, attach.ItemID, p, d);
242 } 306 }
243 catch (Exception e) 307 catch (Exception e)
244 { 308 {
@@ -254,14 +318,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
254 if (!Enabled) 318 if (!Enabled)
255 return; 319 return;
256 320
257// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); 321 if (DebugLevel > 0)
322 m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
323
324 List<SceneObjectGroup> attachments = sp.GetAttachments();
325
326 if (attachments.Count <= 0)
327 return;
328
329 Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>();
330
331 foreach (SceneObjectGroup so in attachments)
332 {
333 // Scripts MUST be snapshotted before the object is
334 // removed from the scene because doing otherwise will
335 // clobber the run flag
336 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
337 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
338 scriptStates[so] = PrepareScriptInstanceForSave(so, false);
339 }
258 340
259 lock (sp.AttachmentsSyncLock) 341 lock (sp.AttachmentsSyncLock)
260 { 342 {
261 foreach (SceneObjectGroup so in sp.GetAttachments()) 343 foreach (SceneObjectGroup so in attachments)
262 { 344 UpdateDetachedObject(sp, so, scriptStates[so]);
263 UpdateDetachedObject(sp, so);
264 }
265 345
266 sp.ClearAttachments(); 346 sp.ClearAttachments();
267 } 347 }
@@ -272,9 +352,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
272 if (!Enabled) 352 if (!Enabled)
273 return; 353 return;
274 354
275// m_log.DebugFormat( 355 if (DebugLevel > 0)
276// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", 356 m_log.DebugFormat(
277// m_scene.RegionInfo.RegionName, sp.Name, silent); 357 "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
358 m_scene.RegionInfo.RegionName, sp.Name, silent);
278 359
279 foreach (SceneObjectGroup sop in sp.GetAttachments()) 360 foreach (SceneObjectGroup sop in sp.GetAttachments())
280 { 361 {
@@ -284,131 +365,141 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
284 sp.ClearAttachments(); 365 sp.ClearAttachments();
285 } 366 }
286 367
287 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) 368 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool append)
288 { 369 {
289 if (!Enabled) 370 if (!Enabled)
290 return false; 371 return false;
291 372
292 if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp)) 373 return AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, addToInventory, false, append);
293 {
294 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
295 return true;
296 }
297
298 return false;
299 } 374 }
300 375
301 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) 376 /// <summary>
377 /// Internal method which actually does all the work for attaching an object.
378 /// </summary>
379 /// <returns>The object attached.</returns>
380 /// <param name='sp'></param>
381 /// <param name='group'>The object to attach.</param>
382 /// <param name='attachmentPt'></param>
383 /// <param name='silent'></param>
384 /// <param name='addToInventory'>If true then add object to user inventory.</param>
385 /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
386 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool resumeScripts, bool append)
302 { 387 {
303 lock (sp.AttachmentsSyncLock)
304 {
305// m_log.DebugFormat( 388// m_log.DebugFormat(
306// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 389// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
307// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 390// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
308 391
309 if (group.GetSittingAvatarsCount() != 0) 392 if (sp.GetAttachments().Contains(group))
310 { 393 {
311// m_log.WarnFormat( 394// m_log.WarnFormat(
312// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", 395// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
313// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); 396// group.Name, group.LocalId, sp.Name, AttachmentPt);
314 397
315 return false; 398 return false;
316 } 399 }
317 400
318 if (sp.GetAttachments(attachmentPt).Contains(group)) 401 if (group.GetSittingAvatarsCount() != 0)
319 { 402 {
320 // m_log.WarnFormat( 403 if (DebugLevel > 0)
321 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", 404 m_log.WarnFormat(
322 // group.Name, group.LocalId, sp.Name, AttachmentPt); 405 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
323 406 group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
324 return false; 407
325 } 408 return false;
326 409 }
327 Vector3 attachPos = group.AbsolutePosition; 410
328 411 Vector3 attachPos = group.AbsolutePosition;
329 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 412
330 // be removed when that functionality is implemented in opensim 413 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
331 attachmentPt &= 0x7f; 414 // be removed when that functionality is implemented in opensim
332 415 attachmentPt &= 0x7f;
333 // If the attachment point isn't the same as the one previously used 416
334 // set it's offset position = 0 so that it appears on the attachment point 417 // If the attachment point isn't the same as the one previously used
335 // and not in a weird location somewhere unknown. 418 // set it's offset position = 0 so that it appears on the attachment point
336 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) 419 // and not in a weird location somewhere unknown.
337 { 420 if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint)
338 attachPos = Vector3.Zero; 421 {
339 } 422 attachPos = Vector3.Zero;
340 423 }
341 // AttachmentPt 0 means the client chose to 'wear' the attachment. 424
342 if (attachmentPt == 0) 425 // AttachmentPt 0 (default) means the client chose to 'wear' the attachment.
343 { 426 if (attachmentPt == (uint)AttachmentPoint.Default)
344 // Check object for stored attachment point 427 {
345 attachmentPt = group.AttachmentPoint; 428 // Check object for stored attachment point
346 } 429 attachmentPt = group.AttachmentPoint;
347 430 }
348 // if we still didn't find a suitable attachment point....... 431
349 if (attachmentPt == 0) 432 // if we still didn't find a suitable attachment point.......
350 { 433 if (attachmentPt == 0)
351 // Stick it on left hand with Zero Offset from the attachment point. 434 {
352 attachmentPt = (uint)AttachmentPoint.LeftHand; 435 // Stick it on left hand with Zero Offset from the attachment point.
353 attachPos = Vector3.Zero; 436 attachmentPt = (uint)AttachmentPoint.LeftHand;
354 } 437 attachPos = Vector3.Zero;
355 438 }
356 if (useAttachData) 439
440 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
441
442 if (attachments.Contains(group))
443 {
444 if (DebugLevel > 0)
445 m_log.WarnFormat(
446 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
447 group.Name, group.LocalId, sp.Name, attachmentPt);
448
449 return false;
450 }
451
452 // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
453 while (attachments.Count >= 5)
454 {
455 if (attachments[0].FromItemID != UUID.Zero)
456 DetachSingleAttachmentToInv(sp, attachments[0]);
457 attachments.RemoveAt(0);
458 }
459
460 // If we're not appending, remove the rest as well
461 if (attachments.Count != 0 && !append)
462 {
463 foreach (SceneObjectGroup g in attachments)
357 { 464 {
358 group.RootPart.RotationOffset = group.RootPart.AttachRotation; 465 if (g.FromItemID != UUID.Zero)
359 attachPos = group.RootPart.AttachOffset; 466 DetachSingleAttachmentToInv(sp, g);
360 if (attachmentPt == 0)
361 {
362 attachmentPt = group.RootPart.AttachPoint;
363 if (attachmentPt == 0)
364 {
365 attachmentPt = (uint)AttachmentPoint.LeftHand;
366 attachPos = Vector3.Zero;
367 }
368 }
369 else if (group.RootPart.AttachPoint != attachmentPt)
370 {
371 attachPos = Vector3.Zero;
372 }
373 } 467 }
468 }
469
470 lock (sp.AttachmentsSyncLock)
471 {
374 group.AttachmentPoint = attachmentPt; 472 group.AttachmentPoint = attachmentPt;
375 group.AbsolutePosition = attachPos; 473 group.AbsolutePosition = attachPos;
376 474
377 if (sp.PresenceType != PresenceType.Npc) 475 if (addToInventory && sp.PresenceType != PresenceType.Npc)
378 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); 476 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append);
379 477
380 AttachToAgent(sp, group, attachmentPt, attachPos, silent); 478 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
479
480 if (resumeScripts)
481 {
482 // Fire after attach, so we don't get messy perms dialogs
483 // 4 == AttachedRez
484 group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
485 group.ResumeScripts();
486 }
487
488 // Do this last so that event listeners have access to all the effects of the attachment
489 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
381 } 490 }
382 491
383 return true; 492 return true;
384 } 493 }
385 494
386 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) 495 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool append)
387 { 496 {
388 // Remove any previous attachments
389 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
390
391 // At the moment we can only deal with a single attachment
392 if (attachments.Count != 0)
393 {
394 if (attachments[0].FromItemID != UUID.Zero)
395 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
396 // Error logging commented because UUID.Zero now means temp attachment
397// else
398// m_log.WarnFormat(
399// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
400// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
401 }
402
403 // Add the new attachment to inventory if we don't already have it. 497 // Add the new attachment to inventory if we don't already have it.
404 if (!temp) 498 UUID newAttachmentItemID = group.FromItemID;
405 { 499 if (newAttachmentItemID == UUID.Zero)
406 UUID newAttachmentItemID = group.FromItemID; 500 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
407 if (newAttachmentItemID == UUID.Zero)
408 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
409 501
410 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); 502 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append);
411 }
412 } 503 }
413 504
414 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 505 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
@@ -421,41 +512,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
421 if (!Enabled) 512 if (!Enabled)
422 return null; 513 return null;
423 514
424// m_log.DebugFormat( 515 if (DebugLevel > 0)
425// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", 516 m_log.DebugFormat(
426// (AttachmentPoint)AttachmentPt, itemID, sp.Name); 517 "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
427 518 (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
428 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
429 // be removed when that functionality is implemented in opensim
430 AttachmentPt &= 0x7f;
431 519
432 // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). 520 // We check the attachments in the avatar appearance here rather than the objects attached to the
433 // This often happens during login - not sure the exact reason. 521 // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are
434 // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the 522 // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done
435 // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login 523 // because pre-outfit folder viewers (most version 1 viewers) require it.
436 // before anything has actually been attached.
437 bool alreadyOn = false; 524 bool alreadyOn = false;
438 List<SceneObjectGroup> existingAttachments = sp.GetAttachments(); 525 List<AvatarAttachment> existingAttachments = sp.Appearance.GetAttachments();
439 foreach (SceneObjectGroup so in existingAttachments) 526 foreach (AvatarAttachment existingAttachment in existingAttachments)
440 { 527 {
441 if (so.FromItemID == itemID) 528 if (existingAttachment.ItemID == itemID)
442 { 529 {
443 alreadyOn = true; 530 alreadyOn = true;
444 break; 531 break;
445 } 532 }
446 } 533 }
447 534
448// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
449 if (alreadyOn) 535 if (alreadyOn)
450 { 536 {
451// m_log.WarnFormat( 537 if (DebugLevel > 0)
452// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", 538 m_log.DebugFormat(
453// sp.Name, itemID, AttachmentPt); 539 "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
540 sp.Name, itemID, AttachmentPt);
454 541
455 return null; 542 return null;
456 } 543 }
457 544
458 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); 545 bool append = (AttachmentPt & 0x80) != 0;
546 AttachmentPt &= 0x7f;
547
548 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append, doc);
459 } 549 }
460 550
461 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) 551 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
@@ -463,13 +553,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
463 if (!Enabled) 553 if (!Enabled)
464 return; 554 return;
465 555
466 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); 556 if (DebugLevel > 0)
467 lock (sp.AttachmentsSyncLock) 557 m_log.DebugFormat(
558 "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}",
559 rezlist.Count, sp.Name, m_scene.Name);
560
561 foreach (KeyValuePair<UUID, uint> rez in rezlist)
468 { 562 {
469 foreach (KeyValuePair<UUID, uint> rez in rezlist) 563 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
470 {
471 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
472 }
473 } 564 }
474 } 565 }
475 566
@@ -483,9 +574,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
483 if (!Enabled) 574 if (!Enabled)
484 return; 575 return;
485 576
486// m_log.DebugFormat( 577 if (DebugLevel > 0)
487// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", 578 m_log.DebugFormat(
488// sp.UUID, soLocalId); 579 "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
580 sp.UUID, soLocalId);
489 581
490 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); 582 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
491 583
@@ -501,9 +593,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
501 if (inventoryID == UUID.Zero) 593 if (inventoryID == UUID.Zero)
502 return; 594 return;
503 595
504// m_log.DebugFormat( 596 if (DebugLevel > 0)
505// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", 597 m_log.DebugFormat(
506// so.Name, so.LocalId, inventoryID); 598 "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
599 so.Name, so.LocalId, inventoryID);
507 600
508 lock (sp.AttachmentsSyncLock) 601 lock (sp.AttachmentsSyncLock)
509 { 602 {
@@ -549,25 +642,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
549 642
550 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) 643 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
551 { 644 {
645 if (so.AttachedAvatar != sp.UUID)
646 {
647 m_log.WarnFormat(
648 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
649 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
650
651 return;
652 }
653
654 if (DebugLevel > 0)
655 m_log.DebugFormat(
656 "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
657 so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
658
659 // Scripts MUST be snapshotted before the object is
660 // removed from the scene because doing otherwise will
661 // clobber the run flag
662 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
663 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
664 string scriptedState = PrepareScriptInstanceForSave(so, true);
665
552 lock (sp.AttachmentsSyncLock) 666 lock (sp.AttachmentsSyncLock)
553 { 667 {
554 // Save avatar attachment information 668 // Save avatar attachment information
555// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 669// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
556 670
557 if (so.AttachedAvatar != sp.UUID)
558 {
559 m_log.WarnFormat(
560 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
561 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
562
563 return;
564 }
565
566 bool changed = sp.Appearance.DetachAttachment(so.FromItemID); 671 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
567 if (changed && m_scene.AvatarFactory != null) 672 if (changed && m_scene.AvatarFactory != null)
568 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 673 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
569 674
570 DetachSingleAttachmentToInvInternal(sp, so); 675 sp.RemoveAttachment(so);
676 UpdateDetachedObject(sp, so, scriptedState);
571 } 677 }
572 } 678 }
573 679
@@ -674,12 +780,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
674 780
675 grp.HasGroupChanged = false; // Prevent it being saved over and over 781 grp.HasGroupChanged = false; // Prevent it being saved over and over
676 } 782 }
677// else 783 else if (DebugLevel > 0)
678// { 784 {
679// m_log.DebugFormat( 785 m_log.DebugFormat(
680// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", 786 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
681// grp.UUID, grp.AttachmentPoint); 787 grp.UUID, grp.AttachmentPoint);
682// } 788 }
683 } 789 }
684 790
685 /// <summary> 791 /// <summary>
@@ -697,9 +803,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
697 private void AttachToAgent( 803 private void AttachToAgent(
698 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 804 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
699 { 805 {
700// m_log.DebugFormat( 806 if (DebugLevel > 0)
701// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", 807 m_log.DebugFormat(
702// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); 808 "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
809 so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
703 810
704 so.DetachFromBackup(); 811 so.DetachFromBackup();
705 812
@@ -722,19 +829,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
722 829
723 if (!silent) 830 if (!silent)
724 { 831 {
725 // Killing it here will cause the client to deselect it 832 if (so.HasPrivateAttachmentPoint)
726 // It then reappears on the avatar, deselected
727 // through the full update below
728 //
729 if (so.IsSelected)
730 { 833 {
731 m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId }); 834 if (DebugLevel > 0)
732 } 835 m_log.DebugFormat(
733 else if (so.HasPrivateAttachmentPoint) 836 "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
734 { 837 so.Name, sp.Name, so.AttachmentPoint);
735// m_log.DebugFormat(
736// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
737// so.Name, sp.Name, so.AttachmentPoint);
738 838
739 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the 839 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the
740 // scene that it's no longer in their awareness. 840 // scene that it's no longer in their awareness.
@@ -745,7 +845,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
745 }); 845 });
746 } 846 }
747 847
748 so.IsSelected = false; // fudge.... 848 // Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update
849 // will succeed, as that will not update if an attachment is selected.
850 so.IsSelected = false; // fudge....
851
749 so.ScheduleGroupForFullUpdate(); 852 so.ScheduleGroupForFullUpdate();
750 } 853 }
751 854
@@ -765,9 +868,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
765 if (m_invAccessModule == null) 868 if (m_invAccessModule == null)
766 return null; 869 return null;
767 870
768 // m_log.DebugFormat( 871 if (DebugLevel > 0)
769 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", 872 m_log.DebugFormat(
770 // grp.Name, grp.LocalId, remoteClient.Name); 873 "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
874 grp.Name, grp.LocalId, sp.Name);
771 875
772 InventoryItemBase newItem 876 InventoryItemBase newItem
773 = m_invAccessModule.CopyToInventory( 877 = m_invAccessModule.CopyToInventory(
@@ -782,8 +886,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
782 return newItem; 886 return newItem;
783 } 887 }
784 888
785 private string GetObjectScriptStates(SceneObjectGroup grp) 889 /// <summary>
890 /// Prepares the script instance for save.
891 /// </summary>
892 /// <remarks>
893 /// This involves triggering the detach event and getting the script state (which also stops the script)
894 /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a
895 /// running script is performing attachment operations.
896 /// </remarks>
897 /// <returns>
898 /// The script state ready for persistence.
899 /// </returns>
900 /// <param name='grp'>
901 /// </param>
902 /// <param name='fireDetachEvent'>
903 /// If true, then fire the script event before we save its state.
904 /// </param>
905 private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent)
786 { 906 {
907 if (fireDetachEvent)
908 m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero);
909
787 using (StringWriter sw = new StringWriter()) 910 using (StringWriter sw = new StringWriter())
788 { 911 {
789 using (XmlTextWriter writer = new XmlTextWriter(sw)) 912 using (XmlTextWriter writer = new XmlTextWriter(sw))
@@ -795,7 +918,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
795 } 918 }
796 } 919 }
797 920
798 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) 921 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState)
799 { 922 {
800 // Don't save attachments for HG visitors, it 923 // Don't save attachments for HG visitors, it
801 // messes up their inventory. When a HG visitor logs 924 // messes up their inventory. When a HG visitor logs
@@ -808,11 +931,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
808 && (m_scene.UserManagementModule == null 931 && (m_scene.UserManagementModule == null
809 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); 932 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
810 933
811 // Scripts MUST be snapshotted before the object is
812 // removed from the scene because doing otherwise will
813 // clobber the run flag
814 string scriptedState = GetObjectScriptStates(so);
815
816 // Remove the object from the scene so no more updates 934 // Remove the object from the scene so no more updates
817 // are sent. Doing this before the below changes will ensure 935 // are sent. Doing this before the below changes will ensure
818 // updates can't cause "HUD artefacts" 936 // updates can't cause "HUD artefacts"
@@ -836,97 +954,75 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
836 so.RemoveScriptInstances(true); 954 so.RemoveScriptInstances(true);
837 } 955 }
838 956
839 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
840 {
841 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
842
843 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
844 sp.RemoveAttachment(so);
845
846 UpdateDetachedObject(sp, so);
847 }
848
849 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 957 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
850 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) 958 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append, XmlDocument doc)
851 { 959 {
852 if (m_invAccessModule == null) 960 if (m_invAccessModule == null)
853 return null; 961 return null;
854 962
855 lock (sp.AttachmentsSyncLock) 963 SceneObjectGroup objatt;
964
965 if (itemID != UUID.Zero)
966 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
967 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
968 false, false, sp.UUID, true);
969 else
970 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
971 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
972 false, false, sp.UUID, true);
973
974 if (objatt == null)
856 { 975 {
857 SceneObjectGroup objatt; 976 m_log.WarnFormat(
977 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
978 itemID, sp.Name, attachmentPt);
858 979
859 if (itemID != UUID.Zero) 980 return null;
860 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 981 }
861 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
862 false, false, sp.UUID, true);
863 else
864 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
865 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
866 false, false, sp.UUID, true);
867 982
868 if (objatt != null) 983 if (DebugLevel > 0)
984 m_log.DebugFormat(
985 "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
986 objatt.Name, sp.Name, attachmentPt, m_scene.Name);
987
988 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
989 objatt.HasGroupChanged = false;
990 bool tainted = false;
991 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
992 tainted = true;
993
994 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
995 // course of events. If not, then it's probably not worth trying to recover the situation
996 // since this is more likely to trigger further exceptions and confuse later debugging. If
997 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
998 // since other normal error conditions will simply return false instead.
999 // This will throw if the attachment fails
1000 try
1001 {
1002 if (doc != null)
869 { 1003 {
870// m_log.DebugFormat( 1004 objatt.LoadScriptState(doc);
871// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", 1005 objatt.ResetOwnerChangeFlag();
872// objatt.Name, sp.Name, attachmentPt, m_scene.Name); 1006 }
873
874 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
875 objatt.HasGroupChanged = false;
876 bool tainted = false;
877 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
878 tainted = true;
879
880 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
881 // course of events. If not, then it's probably not worth trying to recover the situation
882 // since this is more likely to trigger further exceptions and confuse later debugging. If
883 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
884 // since other normal error conditions will simply return false instead.
885 // This will throw if the attachment fails
886 try
887 {
888 AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
889 }
890 catch (Exception e)
891 {
892 m_log.ErrorFormat(
893 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
894 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
895
896 // Make sure the object doesn't stick around and bail
897 sp.RemoveAttachment(objatt);
898 m_scene.DeleteSceneObject(objatt, false);
899 return null;
900 }
901
902 if (tainted)
903 objatt.HasGroupChanged = true;
904 1007
905 if (doc != null) 1008 AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, true, append);
906 { 1009 }
907 objatt.LoadScriptState(doc); 1010 catch (Exception e)
908 objatt.ResetOwnerChangeFlag(); 1011 {
909 } 1012 m_log.ErrorFormat(
1013 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
1014 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
910 1015
911 // Fire after attach, so we don't get messy perms dialogs 1016 // Make sure the object doesn't stick around and bail
912 // 4 == AttachedRez 1017 sp.RemoveAttachment(objatt);
913 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 1018 m_scene.DeleteSceneObject(objatt, false);
914 objatt.ResumeScripts(); 1019 return null;
1020 }
915 1021
916 // Do this last so that event listeners have access to all the effects of the attachment 1022 if (tainted)
917 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 1023 objatt.HasGroupChanged = true;
918 1024
919 return objatt; 1025 return objatt;
920 }
921 else
922 {
923 m_log.WarnFormat(
924 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
925 itemID, sp.Name, attachmentPt);
926 }
927 }
928
929 return null;
930 } 1026 }
931 1027
932 /// <summary> 1028 /// <summary>
@@ -936,7 +1032,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
936 /// <param name="AttachmentPt"></param> 1032 /// <param name="AttachmentPt"></param>
937 /// <param name="itemID"></param> 1033 /// <param name="itemID"></param>
938 /// <param name="att"></param> 1034 /// <param name="att"></param>
939 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 1035 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att, bool append)
940 { 1036 {
941// m_log.DebugFormat( 1037// m_log.DebugFormat(
942// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 1038// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
@@ -959,12 +1055,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
959 if (item == null) 1055 if (item == null)
960 return; 1056 return;
961 1057
962 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 1058 int attFlag = append ? 0x80 : 0;
1059 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID);
963 if (changed && m_scene.AvatarFactory != null) 1060 if (changed && m_scene.AvatarFactory != null)
964 { 1061 {
965// m_log.DebugFormat( 1062 if (DebugLevel > 0)
966// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", 1063 m_log.DebugFormat(
967// sp.Name, att.Name, AttachmentPt); 1064 "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
1065 sp.Name, att.Name, AttachmentPt);
968 1066
969 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 1067 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
970 } 1068 }
@@ -979,9 +1077,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
979 if (!Enabled) 1077 if (!Enabled)
980 return null; 1078 return null;
981 1079
982 // m_log.DebugFormat( 1080 if (DebugLevel > 0)
983 // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 1081 m_log.DebugFormat(
984 // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 1082 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
1083 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name);
985 1084
986 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1085 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
987 1086
@@ -1012,9 +1111,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1012 1111
1013 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) 1112 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
1014 { 1113 {
1015// m_log.DebugFormat( 1114 if (DebugLevel > 0)
1016// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", 1115 m_log.DebugFormat(
1017// objectLocalID, remoteClient.Name, AttachmentPt, silent); 1116 "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
1117 objectLocalID, remoteClient.Name, AttachmentPt, silent);
1018 1118
1019 if (!Enabled) 1119 if (!Enabled)
1020 return; 1120 return;
@@ -1043,16 +1143,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1043 return; 1143 return;
1044 } 1144 }
1045 1145
1046 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 1146 bool append = (AttachmentPt & 0x80) != 0;
1047 // be removed when that functionality is implemented in opensim
1048 AttachmentPt &= 0x7f; 1147 AttachmentPt &= 0x7f;
1049 1148
1050 // Calls attach with a Zero position 1149 // Calls attach with a Zero position
1051 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, false)) 1150 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false, false, append))
1052 { 1151 {
1053// m_log.Debug( 1152 if (DebugLevel > 0)
1054// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId 1153 m_log.Debug(
1055// + ", AttachmentPoint: " + AttachmentPt); 1154 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
1155 + ", AttachmentPoint: " + AttachmentPt);
1056 1156
1057 // Save avatar attachment information 1157 // Save avatar attachment information
1058 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); 1158 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
@@ -1084,17 +1184,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1084 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1184 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
1085 if (sp != null) 1185 if (sp != null)
1086 { 1186 {
1087 lock (sp.AttachmentsSyncLock) 1187 List<SceneObjectGroup> attachments = sp.GetAttachments();
1188
1189 foreach (SceneObjectGroup group in attachments)
1088 { 1190 {
1089 List<SceneObjectGroup> attachments = sp.GetAttachments(); 1191 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
1090
1091 foreach (SceneObjectGroup group in attachments)
1092 { 1192 {
1093 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) 1193 DetachSingleAttachmentToInv(sp, group);
1094 { 1194 return;
1095 DetachSingleAttachmentToInv(sp, group);
1096 return;
1097 }
1098 } 1195 }
1099 } 1196 }
1100 } 1197 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 4e9d3f9..1a38619 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -130,7 +130,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
130 config.AddConfig("Modules"); 130 config.AddConfig("Modules");
131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); 131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
132 132
133 modules.Add(new AttachmentsModule()); 133 AttachmentsModule attMod = new AttachmentsModule();
134 attMod.DebugLevel = 1;
135 modules.Add(attMod);
134 modules.Add(new BasicInventoryAccessModule()); 136 modules.Add(new BasicInventoryAccessModule());
135 } 137 }
136 138
@@ -197,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
197 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); 199 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
198 200
199 m_numberOfAttachEventsFired = 0; 201 m_numberOfAttachEventsFired = 0;
200 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); 202 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false);
201 203
202 // Check status on scene presence 204 // Check status on scene presence
203 Assert.That(sp.HasAttachments(), Is.True); 205 Assert.That(sp.HasAttachments(), Is.True);
@@ -228,6 +230,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
228 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 230 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
229 } 231 }
230 232
233 [Test]
234 public void TestWearAttachmentFromGround()
235 {
236 TestHelpers.InMethod();
237// TestHelpers.EnableLogging();
238
239 Scene scene = CreateTestScene();
240 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
241 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
242
243 SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
244
245 {
246 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
247
248 m_numberOfAttachEventsFired = 0;
249 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false, false);
250
251 // Check status on scene presence
252 Assert.That(sp.HasAttachments(), Is.True);
253 List<SceneObjectGroup> attachments = sp.GetAttachments();
254 Assert.That(attachments.Count, Is.EqualTo(1));
255 SceneObjectGroup attSo = attachments[0];
256 Assert.That(attSo.Name, Is.EqualTo(so.Name));
257 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
258 Assert.That(attSo.IsAttachment);
259 Assert.That(attSo.UsesPhysics, Is.False);
260 Assert.That(attSo.IsTemporary, Is.False);
261
262 // Check item status
263 Assert.That(
264 sp.Appearance.GetAttachpoint(attSo.FromItemID),
265 Is.EqualTo((int)AttachmentPoint.LeftHand));
266
267 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
268 Assert.That(attachmentItem, Is.Not.Null);
269 Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
270
271 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
272 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
273
274 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
275
276 // Check events
277 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
278 }
279
280 // Test wearing a different attachment from the ground.
281 {
282 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false);
283
284 // Check status on scene presence
285 Assert.That(sp.HasAttachments(), Is.True);
286 List<SceneObjectGroup> attachments = sp.GetAttachments();
287 Assert.That(attachments.Count, Is.EqualTo(1));
288 SceneObjectGroup attSo = attachments[0];
289 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
290 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
291 Assert.That(attSo.IsAttachment);
292 Assert.That(attSo.UsesPhysics, Is.False);
293 Assert.That(attSo.IsTemporary, Is.False);
294
295 // Check item status
296 Assert.That(
297 sp.Appearance.GetAttachpoint(attSo.FromItemID),
298 Is.EqualTo((int)AttachmentPoint.LeftHand));
299
300 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
301 Assert.That(attachmentItem, Is.Not.Null);
302 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
303
304 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
305 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
306
307 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
308
309 // Check events
310 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
311 }
312
313 // Test rewearing an already worn attachment from ground. Nothing should happen.
314 {
315 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false);
316
317 // Check status on scene presence
318 Assert.That(sp.HasAttachments(), Is.True);
319 List<SceneObjectGroup> attachments = sp.GetAttachments();
320 Assert.That(attachments.Count, Is.EqualTo(1));
321 SceneObjectGroup attSo = attachments[0];
322 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
323 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
324 Assert.That(attSo.IsAttachment);
325 Assert.That(attSo.UsesPhysics, Is.False);
326 Assert.That(attSo.IsTemporary, Is.False);
327
328 // Check item status
329 Assert.That(
330 sp.Appearance.GetAttachpoint(attSo.FromItemID),
331 Is.EqualTo((int)AttachmentPoint.LeftHand));
332
333 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
334 Assert.That(attachmentItem, Is.Not.Null);
335 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
336
337 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
338 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
339
340 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
341
342 // Check events
343 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
344 }
345 }
346
231 /// <summary> 347 /// <summary>
232 /// Test that we do not attempt to attach an in-world object that someone else is sitting on. 348 /// Test that we do not attempt to attach an in-world object that someone else is sitting on.
233 /// </summary> 349 /// </summary>
@@ -254,7 +370,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
254 sp2.AbsolutePosition = new Vector3(0, 0, 0); 370 sp2.AbsolutePosition = new Vector3(0, 0, 0);
255 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); 371 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
256 372
257 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); 373 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false);
258 374
259 Assert.That(sp.HasAttachments(), Is.False); 375 Assert.That(sp.HasAttachments(), Is.False);
260 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 376 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
@@ -275,29 +391,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
275 391
276 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); 392 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
277 393
278 m_numberOfAttachEventsFired = 0; 394 {
279 scene.AttachmentsModule.RezSingleAttachmentFromInventory( 395 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
280 sp, attItem.ID, (uint)AttachmentPoint.Chest); 396 sp, attItem.ID, (uint)AttachmentPoint.Chest);
281 397
282 // Check scene presence status 398 // Check scene presence status
283 Assert.That(sp.HasAttachments(), Is.True); 399 Assert.That(sp.HasAttachments(), Is.True);
284 List<SceneObjectGroup> attachments = sp.GetAttachments(); 400 List<SceneObjectGroup> attachments = sp.GetAttachments();
285 Assert.That(attachments.Count, Is.EqualTo(1)); 401 Assert.That(attachments.Count, Is.EqualTo(1));
286 SceneObjectGroup attSo = attachments[0]; 402 SceneObjectGroup attSo = attachments[0];
287 Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); 403 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
288 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); 404 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
289 Assert.That(attSo.IsAttachment); 405 Assert.That(attSo.IsAttachment);
290 Assert.That(attSo.UsesPhysics, Is.False); 406 Assert.That(attSo.UsesPhysics, Is.False);
291 Assert.That(attSo.IsTemporary, Is.False); 407 Assert.That(attSo.IsTemporary, Is.False);
408
409 // Check appearance status
410 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
411 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
412 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
413
414 // Check events
415 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
416 }
417
418 // Test attaching an already attached attachment
419 {
420 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
421 sp, attItem.ID, (uint)AttachmentPoint.Chest);
292 422
293 // Check appearance status 423 // Check scene presence status
294 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); 424 Assert.That(sp.HasAttachments(), Is.True);
295 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 425 List<SceneObjectGroup> attachments = sp.GetAttachments();
426 Assert.That(attachments.Count, Is.EqualTo(1));
427 SceneObjectGroup attSo = attachments[0];
428 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
429 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
430 Assert.That(attSo.IsAttachment);
431 Assert.That(attSo.UsesPhysics, Is.False);
432 Assert.That(attSo.IsTemporary, Is.False);
433
434 // Check appearance status
435 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
436 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
437 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
438
439 // Check events
440 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
441 }
442 }
296 443
297 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 444 /// <summary>
445 /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
446 /// </summary>
447 [Test]
448 public void TestWearAttachmentFromInventory()
449 {
450 TestHelpers.InMethod();
451// TestHelpers.EnableLogging();
298 452
299 // Check events 453 Scene scene = CreateTestScene();
300 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 454 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
455 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
456
457 InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
458 InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
459
460 {
461 m_numberOfAttachEventsFired = 0;
462 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
463
464 // default attachment point is currently the left hand.
465 Assert.That(sp.HasAttachments(), Is.True);
466 List<SceneObjectGroup> attachments = sp.GetAttachments();
467 Assert.That(attachments.Count, Is.EqualTo(1));
468 SceneObjectGroup attSo = attachments[0];
469 Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
470 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
471 Assert.That(attSo.IsAttachment);
472
473 // Check appearance status
474 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
475 Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
476 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
477
478 // Check events
479 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
480 }
481
482 // Test wearing a second attachment at the same position
483 // Until multiple attachments at one point is implemented, this will remove the first attachment
484 // This test relies on both attachments having the same default attachment point (in this case LeftHand
485 // since none other has been set).
486 {
487 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
488
489 // default attachment point is currently the left hand.
490 Assert.That(sp.HasAttachments(), Is.True);
491 List<SceneObjectGroup> attachments = sp.GetAttachments();
492 Assert.That(attachments.Count, Is.EqualTo(1));
493 SceneObjectGroup attSo = attachments[0];
494 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
495 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
496 Assert.That(attSo.IsAttachment);
497
498 // Check appearance status
499 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
500 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
501 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
502
503 // Check events
504 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
505 }
506
507 // Test wearing an already attached attachment
508 {
509 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
510
511 // default attachment point is currently the left hand.
512 Assert.That(sp.HasAttachments(), Is.True);
513 List<SceneObjectGroup> attachments = sp.GetAttachments();
514 Assert.That(attachments.Count, Is.EqualTo(1));
515 SceneObjectGroup attSo = attachments[0];
516 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
517 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
518 Assert.That(attSo.IsAttachment);
519
520 // Check appearance status
521 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
522 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
523 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
524
525 // Check events
526 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
527 }
301 } 528 }
302 529
303 /// <summary> 530 /// <summary>
@@ -503,7 +730,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
503 public void TestRezAttachmentsOnAvatarEntrance() 730 public void TestRezAttachmentsOnAvatarEntrance()
504 { 731 {
505 TestHelpers.InMethod(); 732 TestHelpers.InMethod();
506// log4net.Config.XmlConfigurator.Configure(); 733// TestHelpers.EnableLogging();
507 734
508 Scene scene = CreateTestScene(); 735 Scene scene = CreateTestScene();
509 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 736 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
@@ -604,7 +831,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
604 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); 831 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
605 832
606 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); 833 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
607 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); 834
835 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
836 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
837 List<TestClient> destinationTestClients = new List<TestClient>();
838 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
839
840 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
608 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); 841 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
609 842
610 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); 843 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@@ -623,7 +856,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
623 teleportLookAt, 856 teleportLookAt,
624 (uint)TeleportFlags.ViaLocation); 857 (uint)TeleportFlags.ViaLocation);
625 858
626 ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); 859 destinationTestClients[0].CompleteMovement();
627 860
628 // Check attachments have made it into sceneB 861 // Check attachments have made it into sceneB
629 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); 862 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 7ec2860..bc79944 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41 41
42using Mono.Addins; 42using Mono.Addins;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 45namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
45{ 46{
@@ -322,6 +323,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
322 323
323 if (asset != null) 324 if (asset != null)
324 { 325 {
326 // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars
327 asset.ID = asset.FullID.ToString();
328
325 asset.Temporary = false; 329 asset.Temporary = false;
326 asset.Local = false; 330 asset.Local = false;
327 m_scene.AssetService.Store(asset); 331 m_scene.AssetService.Store(asset);
@@ -358,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
358 362
359 public void QueueAppearanceSave(UUID agentid) 363 public void QueueAppearanceSave(UUID agentid)
360 { 364 {
361 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); 365// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
362 366
363 // 10000 ticks per millisecond, 1000 milliseconds per second 367 // 10000 ticks per millisecond, 1000 milliseconds per second
364 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); 368 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@@ -655,7 +659,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
655 return; 659 return;
656 } 660 }
657 661
658 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); 662// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
659 663
660 // This could take awhile since it needs to pull inventory 664 // This could take awhile since it needs to pull inventory
661 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape 665 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
@@ -664,6 +668,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
664 // multiple save requests. 668 // multiple save requests.
665 SetAppearanceAssets(sp.UUID, sp.Appearance); 669 SetAppearanceAssets(sp.UUID, sp.Appearance);
666 670
671// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
672// foreach (AvatarAttachment att in attachments)
673// {
674// m_log.DebugFormat(
675// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
676// sp.Name, att.ItemID, att.AttachPoint);
677// }
678
667 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); 679 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
668 680
669 // Trigger this here because it's the final step in the set/queue/save process for appearance setting. 681 // Trigger this here because it's the final step in the set/queue/save process for appearance setting.
@@ -674,26 +686,70 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
674 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) 686 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
675 { 687 {
676 IInventoryService invService = m_scene.InventoryService; 688 IInventoryService invService = m_scene.InventoryService;
677 689 bool resetwearable = false;
678 if (invService.GetRootFolder(userID) != null) 690 if (invService.GetRootFolder(userID) != null)
679 { 691 {
680 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) 692 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
681 { 693 {
682 for (int j = 0; j < appearance.Wearables[i].Count; j++) 694 for (int j = 0; j < appearance.Wearables[i].Count; j++)
683 { 695 {
696 // Check if the default wearables are not set
684 if (appearance.Wearables[i][j].ItemID == UUID.Zero) 697 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
698 {
699 switch ((WearableType) i)
700 {
701 case WearableType.Eyes:
702 case WearableType.Hair:
703 case WearableType.Shape:
704 case WearableType.Skin:
705 //case WearableType.Underpants:
706 TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
707 resetwearable = true;
708 m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values.");
709 resetwearable = true;
710 break;
711
712 }
685 continue; 713 continue;
714 }
686 715
687 // Ignore ruth's assets 716 // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1
688 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) 717 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
718 {
719 switch ((WearableType)i)
720 {
721 case WearableType.Eyes:
722 case WearableType.Hair:
723 case WearableType.Shape:
724 case WearableType.Skin:
725 //case WearableType.Underpants:
726 TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
727
728 m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i);
729 resetwearable = true;
730 break;
731
732 }
689 continue; 733 continue;
690 734 }
735
691 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); 736 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
692 baseItem = invService.GetItem(baseItem); 737 baseItem = invService.GetItem(baseItem);
693 738
694 if (baseItem != null) 739 if (baseItem != null)
695 { 740 {
696 appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID); 741 appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
742 int unmodifiedWearableIndexForClosure = i;
743 m_scene.AssetService.Get(baseItem.AssetID.ToString(), this,
744 delegate(string x, object y, AssetBase z)
745 {
746 if (z == null)
747 {
748 TryAndRepairBrokenWearable(
749 (WearableType)unmodifiedWearableIndexForClosure, invService,
750 userID, appearance);
751 }
752 });
697 } 753 }
698 else 754 else
699 { 755 {
@@ -701,17 +757,236 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
701 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", 757 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
702 appearance.Wearables[i][j].ItemID, (WearableType)i); 758 appearance.Wearables[i][j].ItemID, (WearableType)i);
703 759
704 appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID); 760 TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
761 resetwearable = true;
762
705 } 763 }
706 } 764 }
707 } 765 }
766
767 // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
768 if (appearance.Wearables[(int) WearableType.Eyes] == null)
769 {
770 m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes));
771
772 TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
773 resetwearable = true;
774 }
775 else
776 {
777 if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero)
778 {
779 m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}",
780 appearance.Wearables[(int) WearableType.Eyes][0].ItemID,
781 appearance.Wearables[(int) WearableType.Eyes][0].AssetID);
782 TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
783 resetwearable = true;
784
785 }
786
787 }
788 // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
789 if (appearance.Wearables[(int)WearableType.Shape] == null)
790 {
791 m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape));
792
793 TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
794 resetwearable = true;
795 }
796 else
797 {
798 if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero)
799 {
800 m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}",
801 appearance.Wearables[(int)WearableType.Shape][0].ItemID,
802 appearance.Wearables[(int)WearableType.Shape][0].AssetID);
803 TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
804 resetwearable = true;
805
806 }
807
808 }
809 // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
810 if (appearance.Wearables[(int)WearableType.Hair] == null)
811 {
812 m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair));
813
814 TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
815 resetwearable = true;
816 }
817 else
818 {
819 if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero)
820 {
821 m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}",
822 appearance.Wearables[(int)WearableType.Hair][0].ItemID,
823 appearance.Wearables[(int)WearableType.Hair][0].AssetID);
824 TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
825 resetwearable = true;
826
827 }
828
829 }
830 // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
831 if (appearance.Wearables[(int)WearableType.Skin] == null)
832 {
833 m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin));
834
835 TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
836 resetwearable = true;
837 }
838 else
839 {
840 if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero)
841 {
842 m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}",
843 appearance.Wearables[(int)WearableType.Skin][0].ItemID,
844 appearance.Wearables[(int)WearableType.Skin][0].AssetID);
845 TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
846 resetwearable = true;
847
848 }
849
850 }
851 if (resetwearable)
852 {
853 ScenePresence presence = null;
854 if (m_scene.TryGetScenePresence(userID, out presence))
855 {
856 presence.ControllingClient.SendWearables(presence.Appearance.Wearables,
857 presence.Appearance.Serial++);
858 }
859 }
860
708 } 861 }
709 else 862 else
710 { 863 {
711 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); 864 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
712 } 865 }
713 } 866 }
867 private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance)
868 {
869 UUID defaultwearable = GetDefaultItem(type);
870 if (defaultwearable != UUID.Zero)
871 {
872 UUID newInvItem = UUID.Random();
873 InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID)
874 {
875 AssetID =
876 defaultwearable,
877 AssetType
878 =
879 (int)
880 AssetType
881 .Bodypart,
882 CreatorId
883 =
884 userID
885 .ToString
886 (),
887 //InvType = (int)InventoryType.Wearable,
888
889 Description
890 =
891 "Failed Wearable Replacement",
892 Folder =
893 invService
894 .GetFolderForType
895 (userID,
896 AssetType
897 .Bodypart)
898 .ID,
899 Flags = (uint) type,
900 Name = Enum.GetName(typeof (WearableType), type),
901 BasePermissions = (uint) PermissionMask.Copy,
902 CurrentPermissions = (uint) PermissionMask.Copy,
903 EveryOnePermissions = (uint) PermissionMask.Copy,
904 GroupPermissions = (uint) PermissionMask.Copy,
905 NextPermissions = (uint) PermissionMask.Copy
906 };
907 invService.AddItem(itembase);
908 UUID LinkInvItem = UUID.Random();
909 itembase = new InventoryItemBase(LinkInvItem, userID)
910 {
911 AssetID =
912 newInvItem,
913 AssetType
914 =
915 (int)
916 AssetType
917 .Link,
918 CreatorId
919 =
920 userID
921 .ToString
922 (),
923 InvType = (int) InventoryType.Wearable,
924
925 Description
926 =
927 "Failed Wearable Replacement",
928 Folder =
929 invService
930 .GetFolderForType
931 (userID,
932 AssetType
933 .CurrentOutfitFolder)
934 .ID,
935 Flags = (uint) type,
936 Name = Enum.GetName(typeof (WearableType), type),
937 BasePermissions = (uint) PermissionMask.Copy,
938 CurrentPermissions = (uint) PermissionMask.Copy,
939 EveryOnePermissions = (uint) PermissionMask.Copy,
940 GroupPermissions = (uint) PermissionMask.Copy,
941 NextPermissions = (uint) PermissionMask.Copy
942 };
943 invService.AddItem(itembase);
944 appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type));
945 ScenePresence presence = null;
946 if (m_scene.TryGetScenePresence(userID, out presence))
947 {
948 m_scene.SendInventoryUpdate(presence.ControllingClient,
949 invService.GetFolderForType(userID,
950 AssetType
951 .CurrentOutfitFolder),
952 false, true);
953 }
954 }
955 }
956 private UUID GetDefaultItem(WearableType wearable)
957 {
958 // These are ruth
959 UUID ret = UUID.Zero;
960 switch (wearable)
961 {
962 case WearableType.Eyes:
963 ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7");
964 break;
965 case WearableType.Hair:
966 ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66");
967 break;
968 case WearableType.Pants:
969 ret = new UUID("00000000-38f9-1111-024e-222222111120");
970 break;
971 case WearableType.Shape:
972 ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
973 break;
974 case WearableType.Shirt:
975 ret = new UUID("00000000-38f9-1111-024e-222222111110");
976 break;
977 case WearableType.Skin:
978 ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb");
979 break;
980 case WearableType.Undershirt:
981 ret = new UUID("16499ebb-3208-ec27-2def-481881728f47");
982 break;
983 case WearableType.Underpants:
984 ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d");
985 break;
986 }
714 987
988 return ret;
989 }
715 #endregion 990 #endregion
716 991
717 #region Client Event Handlers 992 #region Client Event Handlers
@@ -824,7 +1099,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
824 } 1099 }
825 1100
826 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); 1101 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
827 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 1102 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
828 } 1103 }
829 } 1104 }
830} 1105}
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/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 4c3f1cc..174642d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
256 // If camera is moved into client, then camera position can be used 256 // If camera is moved into client, then camera position can be used
257 // MT: No, it can't, as chat is heard from the avatar position, not 257 // MT: No, it can't, as chat is heard from the avatar position, not
258 // the camera position. 258 // the camera position.
259 s.ForEachRootScenePresence( 259 s.ForEachScenePresence(
260 delegate(ScenePresence presence) 260 delegate(ScenePresence presence)
261 { 261 {
262 if (destination != UUID.Zero && presence.UUID != destination) 262 if (destination != UUID.Zero && presence.UUID != destination)
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
index 5ec0ea9..b44a5c9 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -36,6 +36,7 @@ using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Services.Interfaces; 37using OpenSim.Services.Interfaces;
38using Mono.Addins; 38using Mono.Addins;
39using PermissionMask = OpenSim.Framework.PermissionMask;
39 40
40namespace OpenSim.Region.CoreModules.Avatar.Friends 41namespace OpenSim.Region.CoreModules.Avatar.Friends
41{ 42{
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/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 9fa9be1..fa8c3f3 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -67,9 +67,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
67 protected Scene m_scene; 67 protected Scene m_scene;
68 protected IDialogModule m_dialogModule; 68 protected IDialogModule m_dialogModule;
69 69
70 protected Dictionary<UUID, string> m_capsDict =
71 new Dictionary<UUID, string>();
72
73 protected IDialogModule DialogModule 70 protected IDialogModule DialogModule
74 { 71 {
75 get 72 get
@@ -91,7 +88,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
91 m_scene.RegisterModuleInterface<IGodsModule>(this); 88 m_scene.RegisterModuleInterface<IGodsModule>(this);
92 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 89 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
93 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; 90 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
94 m_scene.EventManager.OnClientClosed += OnClientClosed;
95 scene.EventManager.OnIncomingInstantMessage += 91 scene.EventManager.OnIncomingInstantMessage +=
96 OnIncomingInstantMessage; 92 OnIncomingInstantMessage;
97 } 93 }
@@ -127,15 +123,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
127 client.OnRequestGodlikePowers -= RequestGodlikePowers; 123 client.OnRequestGodlikePowers -= RequestGodlikePowers;
128 } 124 }
129 125
130 private void OnClientClosed(UUID agentID, Scene scene)
131 {
132 m_capsDict.Remove(agentID);
133 }
134
135 private void OnRegisterCaps(UUID agentID, Caps caps) 126 private void OnRegisterCaps(UUID agentID, Caps caps)
136 { 127 {
137 string uri = "/CAPS/" + UUID.Random(); 128 string uri = "/CAPS/" + UUID.Random();
138 m_capsDict[agentID] = uri;
139 129
140 caps.RegisterHandler("UntrustedSimulatorMessage", 130 caps.RegisterHandler("UntrustedSimulatorMessage",
141 new RestStreamHandler("POST", uri, 131 new RestStreamHandler("POST", uri,
@@ -288,8 +278,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
288 if (sp.IsChildAgent) 278 if (sp.IsChildAgent)
289 return; 279 return;
290 sp.ControllingClient.Kick(reason); 280 sp.ControllingClient.Kick(reason);
291 sp.MakeChildAgent(); 281 sp.Scene.IncomingCloseAgent(sp.UUID, true);
292 sp.ControllingClient.Close();
293 } 282 }
294 283
295 private void OnIncomingInstantMessage(GridInstantMessage msg) 284 private void OnIncomingInstantMessage(GridInstantMessage msg)
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/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index dc2b0e0..659b178 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -161,7 +161,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
161 string filePath = "ERROR"; 161 string filePath = "ERROR";
162 162
163 List<InventoryFolderBase> folderCandidates 163 List<InventoryFolderBase> folderCandidates
164 = InventoryArchiveUtils.FindFolderByPath( 164 = InventoryArchiveUtils.FindFoldersByPath(
165 m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); 165 m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath);
166 166
167 if (folderCandidates.Count == 0) 167 if (folderCandidates.Count == 0)
@@ -296,7 +296,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
296 // iar name and try to find that instead. 296 // iar name and try to find that instead.
297 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); 297 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
298 List<InventoryFolderBase> folderCandidates 298 List<InventoryFolderBase> folderCandidates
299 = InventoryArchiveUtils.FindFolderByPath( 299 = InventoryArchiveUtils.FindFoldersByPath(
300 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); 300 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath);
301 301
302 if (folderCandidates.Count != 0) 302 if (folderCandidates.Count != 0)
@@ -487,6 +487,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
487 { 487 {
488// m_log.DebugFormat( 488// m_log.DebugFormat(
489// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); 489// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
490
491 if (coa.Objects.Count == 0)
492 {
493 m_log.WarnFormat(
494 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components",
495 assetId);
496 return false;
497 }
490 498
491 sceneObjects.AddRange(coa.Objects); 499 sceneObjects.AddRange(coa.Objects);
492 } 500 }
@@ -495,7 +503,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
495 SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 503 SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
496 504
497 if (deserializedObject != null) 505 if (deserializedObject != null)
506 {
498 sceneObjects.Add(deserializedObject); 507 sceneObjects.Add(deserializedObject);
508 }
509 else
510 {
511 m_log.WarnFormat(
512 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed",
513 assetId);
514
515 return false;
516 }
499 } 517 }
500 518
501 foreach (SceneObjectGroup sog in sceneObjects) 519 foreach (SceneObjectGroup sog in sceneObjects)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
index 0d90a15..dbaf2aa 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
@@ -52,13 +52,82 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
52 /// <summary> 52 /// <summary>
53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder 53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder
54 /// </summary> 54 /// </summary>
55 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors
57 ///
58 /// FIXME: We have no way of distinguishing folders with the same path
55 /// 59 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
61 /// </remarks>
62 /// <param name="inventoryService">
63 /// Inventory service to query
64 /// </param>
65 /// <param name="userId">
66 /// User id to search
67 /// </param>
68 /// <param name="path">
69 /// The path to the required folder.
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param>
72 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
73 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
74 public static InventoryFolderBase FindFolderByPath(
75 IInventoryService inventoryService, UUID userId, string path)
76 {
77 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, userId, path);
78
79 if (folders.Count == 0)
80 return null;
81 else
82 return folders[0];
83 }
84
85 /// <summary>
86 /// Find a folder given a PATH_DELIMITER delimited path starting from a given folder
87 /// </summary>
88 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors 89 /// This method does not handle paths that contain multiple delimitors
57 /// 90 ///
58 /// FIXME: We have no way of distinguishing folders with the same path 91 /// FIXME: We have no way of distinguishing folders with the same path
59 /// 92 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 93 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
94 /// </remarks>
95 /// <param name="inventoryService">
96 /// Inventory service to query
97 /// </param>
98 /// <param name="startFolder">
99 /// The folder from which the path starts
100 /// </param>
101 /// <param name="path">
102 /// The path to the required folder.
103 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
104 /// </param>
105 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
106 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
107 public static InventoryFolderBase FindFolderByPath(
108 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
109 {
110 if (null == startFolder)
111 return null;
112
113 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, startFolder, path);
114
115 if (folders.Count == 0)
116 return null;
117 else
118 return folders[0];
119 }
120
121 /// <summary>
122 /// Find a set of folders given a PATH_DELIMITER delimited path starting from a user's root folder
123 /// </summary>
124 /// <remarks>
125 /// This method does not handle paths that contain multiple delimitors
126 ///
127 /// FIXME: We have no way of distinguishing folders with the same path
61 /// 128 ///
129 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
130 /// </remarks>
62 /// <param name="inventoryService"> 131 /// <param name="inventoryService">
63 /// Inventory service to query 132 /// Inventory service to query
64 /// </param> 133 /// </param>
@@ -70,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 139 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param> 140 /// </param>
72 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 141 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
73 public static List<InventoryFolderBase> FindFolderByPath( 142 public static List<InventoryFolderBase> FindFoldersByPath(
74 IInventoryService inventoryService, UUID userId, string path) 143 IInventoryService inventoryService, UUID userId, string path)
75 { 144 {
76 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 145 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
@@ -78,19 +147,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
78 if (null == rootFolder) 147 if (null == rootFolder)
79 return new List<InventoryFolderBase>(); 148 return new List<InventoryFolderBase>();
80 149
81 return FindFolderByPath(inventoryService, rootFolder, path); 150 return FindFoldersByPath(inventoryService, rootFolder, path);
82 } 151 }
83 152
84 /// <summary> 153 /// <summary>
85 /// Find a folder given a PATH_DELIMITER delimited path starting from this folder 154 /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder
86 /// </summary> 155 /// </summary>
87 /// 156 /// <remarks>
88 /// This method does not handle paths that contain multiple delimitors 157 /// This method does not handle paths that contain multiple delimitors
89 /// 158 ///
90 /// FIXME: We have no way of distinguishing folders with the same path. 159 /// FIXME: We have no way of distinguishing folders with the same path.
91 /// 160 ///
92 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 161 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
93 /// 162 /// </remarks>
94 /// <param name="inventoryService"> 163 /// <param name="inventoryService">
95 /// Inventory service to query 164 /// Inventory service to query
96 /// </param> 165 /// </param>
@@ -102,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
102 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 171 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
103 /// </param> 172 /// </param>
104 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 173 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
105 public static List<InventoryFolderBase> FindFolderByPath( 174 public static List<InventoryFolderBase> FindFoldersByPath(
106 IInventoryService inventoryService, InventoryFolderBase startFolder, string path) 175 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
107 { 176 {
108 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>(); 177 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>();
@@ -133,12 +202,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
133 202
134 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); 203 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);
135 204
205// m_log.DebugFormat(
206// "Found {0} folders in {1} for {2}", contents.Folders.Count, startFolder.Name, startFolder.Owner);
207
136 foreach (InventoryFolderBase folder in contents.Folders) 208 foreach (InventoryFolderBase folder in contents.Folders)
137 { 209 {
138 if (folder.Name == components[0]) 210 if (folder.Name == components[0])
139 { 211 {
140 if (components.Length > 1) 212 if (components.Length > 1)
141 foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1])); 213 foundFolders.AddRange(FindFoldersByPath(inventoryService, folder, components[1]));
142 else 214 else
143 foundFolders.Add(folder); 215 foundFolders.Add(folder);
144 } 216 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index d0e88f6..4ec8ae7 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 }
@@ -266,6 +272,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
266 saveFolderContentsOnly = true; 272 saveFolderContentsOnly = true;
267 maxComponentIndex--; 273 maxComponentIndex--;
268 } 274 }
275 else if (maxComponentIndex == -1)
276 {
277 // If the user has just specified "/", then don't save the root "My Inventory" folder. This is
278 // more intuitive then requiring the user to specify "/*" for this.
279 saveFolderContentsOnly = true;
280 }
269 281
270 m_invPath = String.Empty; 282 m_invPath = String.Empty;
271 for (int i = 0; i <= maxComponentIndex; i++) 283 for (int i = 0; i <= maxComponentIndex; i++)
@@ -283,7 +295,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
283 { 295 {
284 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); 296 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER));
285 List<InventoryFolderBase> candidateFolders 297 List<InventoryFolderBase> candidateFolders
286 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, rootFolder, m_invPath); 298 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, rootFolder, m_invPath);
287 if (candidateFolders.Count > 0) 299 if (candidateFolders.Count > 0)
288 inventoryFolder = candidateFolders[0]; 300 inventoryFolder = candidateFolders[0];
289 } 301 }
@@ -350,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
350 { 362 {
351 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); 363 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified");
352 364
353 ReceivedAllAssets(new List<UUID>(), new List<UUID>()); 365 ReceivedAllAssets(new List<UUID>(), new List<UUID>(), false);
354 } 366 }
355 } 367 }
356 catch (Exception) 368 catch (Exception)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
index 6eb3605..95f562e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
@@ -48,125 +48,9 @@ using OpenSim.Tests.Common.Mock;
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 49{
50 [TestFixture] 50 [TestFixture]
51 public class PathTests : InventoryArchiveTestCase 51 public class InventoryArchiveLoadPathTests : InventoryArchiveTestCase
52 { 52 {
53 /// <summary> 53 /// <summary>
54 /// Test saving an inventory path to a V0.1 OpenSim Inventory Archive
55 /// (subject to change since there is no fixed format yet).
56 /// </summary>
57 [Test]
58 public void TestSavePathToIarV0_1()
59 {
60 TestHelpers.InMethod();
61// log4net.Config.XmlConfigurator.Configure();
62
63 InventoryArchiverModule archiverModule = new InventoryArchiverModule();
64
65 Scene scene = new SceneHelpers().SetupScene();
66 SceneHelpers.SetupSceneModules(scene, archiverModule);
67
68 // Create user
69 string userFirstName = "Jock";
70 string userLastName = "Stirrup";
71 string userPassword = "troll";
72 UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020");
73 UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, userPassword);
74
75 // Create asset
76 SceneObjectGroup object1;
77 SceneObjectPart part1;
78 {
79 string partName = "My Little Dog Object";
80 UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
81 PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
82 Vector3 groupPosition = new Vector3(10, 20, 30);
83 Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
84 Vector3 offsetPosition = new Vector3(5, 10, 15);
85
86 part1 = new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition);
87 part1.Name = partName;
88
89 object1 = new SceneObjectGroup(part1);
90 scene.AddNewSceneObject(object1, false);
91 }
92
93 UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
94 AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1);
95 scene.AssetService.Store(asset1);
96
97 // Create item
98 UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
99 InventoryItemBase item1 = new InventoryItemBase();
100 item1.Name = "My Little Dog";
101 item1.AssetID = asset1.FullID;
102 item1.ID = item1Id;
103 InventoryFolderBase objsFolder
104 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0];
105 item1.Folder = objsFolder.ID;
106 scene.AddInventoryItem(item1);
107
108 MemoryStream archiveWriteStream = new MemoryStream();
109 archiverModule.OnInventoryArchiveSaved += SaveCompleted;
110
111 // Test saving a particular path
112 mre.Reset();
113 archiverModule.ArchiveInventory(
114 Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
115 mre.WaitOne(60000, false);
116
117 byte[] archive = archiveWriteStream.ToArray();
118 MemoryStream archiveReadStream = new MemoryStream(archive);
119 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
120
121 //bool gotControlFile = false;
122 bool gotObject1File = false;
123 //bool gotObject2File = false;
124 string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1);
125 string expectedObject1FilePath = string.Format(
126 "{0}{1}{2}",
127 ArchiveConstants.INVENTORY_PATH,
128 InventoryArchiveWriteRequest.CreateArchiveFolderName(objsFolder),
129 expectedObject1FileName);
130
131 string filePath;
132 TarArchiveReader.TarEntryType tarEntryType;
133
134// Console.WriteLine("Reading archive");
135
136 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
137 {
138// Console.WriteLine("Got {0}", filePath);
139
140// if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
141// {
142// gotControlFile = true;
143// }
144
145 if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml"))
146 {
147// string fileName = filePath.Remove(0, "Objects/".Length);
148//
149// if (fileName.StartsWith(part1.Name))
150// {
151 Assert.That(expectedObject1FilePath, Is.EqualTo(filePath));
152 gotObject1File = true;
153// }
154// else if (fileName.StartsWith(part2.Name))
155// {
156// Assert.That(fileName, Is.EqualTo(expectedObject2FileName));
157// gotObject2File = true;
158// }
159 }
160 }
161
162// Assert.That(gotControlFile, Is.True, "No control file in archive");
163 Assert.That(gotObject1File, Is.True, "No item1 file in archive");
164// Assert.That(gotObject2File, Is.True, "No object2 file in archive");
165
166 // TODO: Test presence of more files and contents of files.
167 }
168
169 /// <summary>
170 /// Test loading an IAR to various different inventory paths. 54 /// Test loading an IAR to various different inventory paths.
171 /// </summary> 55 /// </summary>
172 [Test] 56 [Test]
@@ -193,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
193 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); 77 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
194 78
195 // Now try loading to a root child folder 79 // Now try loading to a root child folder
196 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA"); 80 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false);
197 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); 81 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray());
198 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); 82 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream);
199 83
@@ -202,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
202 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); 86 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2");
203 87
204 // Now try loading to a more deeply nested folder 88 // Now try loading to a more deeply nested folder
205 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC"); 89 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC", false);
206 archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); 90 archiveReadStream = new MemoryStream(archiveReadStream.ToArray());
207 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); 91 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream);
208 92
@@ -287,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
287 item1.AssetID = asset1.FullID; 171 item1.AssetID = asset1.FullID;
288 item1.ID = item1Id; 172 item1.ID = item1Id;
289 InventoryFolderBase objsFolder 173 InventoryFolderBase objsFolder
290 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0]; 174 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0];
291 item1.Folder = objsFolder.ID; 175 item1.Folder = objsFolder.ID;
292 scene.AddInventoryItem(item1); 176 scene.AddInventoryItem(item1);
293 177
@@ -351,12 +235,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
351 foldersCreated, nodesLoaded); 235 foldersCreated, nodesLoaded);
352 236
353 List<InventoryFolderBase> folder1Candidates 237 List<InventoryFolderBase> folder1Candidates
354 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 238 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
355 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 239 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
356 240
357 InventoryFolderBase folder1 = folder1Candidates[0]; 241 InventoryFolderBase folder1 = folder1Candidates[0];
358 List<InventoryFolderBase> folder2aCandidates 242 List<InventoryFolderBase> folder2aCandidates
359 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 243 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
360 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 244 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
361 } 245 }
362 246
@@ -368,17 +252,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
368 foldersCreated, nodesLoaded); 252 foldersCreated, nodesLoaded);
369 253
370 List<InventoryFolderBase> folder1Candidates 254 List<InventoryFolderBase> folder1Candidates
371 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 255 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
372 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 256 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
373 257
374 InventoryFolderBase folder1 = folder1Candidates[0]; 258 InventoryFolderBase folder1 = folder1Candidates[0];
375 259
376 List<InventoryFolderBase> folder2aCandidates 260 List<InventoryFolderBase> folder2aCandidates
377 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 261 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
378 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 262 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
379 263
380 List<InventoryFolderBase> folder2bCandidates 264 List<InventoryFolderBase> folder2bCandidates
381 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2bName); 265 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName);
382 Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); 266 Assert.That(folder2bCandidates.Count, Is.EqualTo(1));
383 } 267 }
384 } 268 }
@@ -401,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
401 285
402 InventoryFolderBase folder1 286 InventoryFolderBase folder1
403 = UserInventoryHelpers.CreateInventoryFolder( 287 = UserInventoryHelpers.CreateInventoryFolder(
404 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 288 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
405 289
406 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 290 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
407 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 291 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
@@ -414,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
414 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 298 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
415 299
416 List<InventoryFolderBase> folder1PostCandidates 300 List<InventoryFolderBase> folder1PostCandidates
417 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 301 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
418 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); 302 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2));
419 303
420 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. 304 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder.
@@ -430,7 +314,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
430// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); 314// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID));
431 315
432 List<InventoryFolderBase> folder2PostCandidates 316 List<InventoryFolderBase> folder2PostCandidates
433 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); 317 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b");
434 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 318 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
435 } 319 }
436 320
@@ -452,7 +336,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
452 336
453 InventoryFolderBase folder1 337 InventoryFolderBase folder1
454 = UserInventoryHelpers.CreateInventoryFolder( 338 = UserInventoryHelpers.CreateInventoryFolder(
455 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 339 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
456 340
457 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 341 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
458 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 342 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
@@ -465,13 +349,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
465 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 349 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
466 350
467 List<InventoryFolderBase> folder1PostCandidates 351 List<InventoryFolderBase> folder1PostCandidates
468 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 352 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
469 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); 353 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
470 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); 354 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
471 355
472 List<InventoryFolderBase> folder2PostCandidates 356 List<InventoryFolderBase> folder2PostCandidates
473 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b"); 357 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b");
474 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 358 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
475 } 359 }
476 } 360 }
477} \ No newline at end of file 361}
362
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
new file mode 100644
index 0000000..1b521fc
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
@@ -0,0 +1,194 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Threading;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{
50 [TestFixture]
51 public class InventoryArchiveLoadTests : InventoryArchiveTestCase
52 {
53 protected TestScene m_scene;
54 protected InventoryArchiverModule m_archiverModule;
55
56 [SetUp]
57 public override void SetUp()
58 {
59 base.SetUp();
60
61 SerialiserModule serialiserModule = new SerialiserModule();
62 m_archiverModule = new InventoryArchiverModule();
63
64 m_scene = new SceneHelpers().SetupScene();
65 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
66 }
67
68 [Test]
69 public void TestLoadCoalesecedItem()
70 {
71 TestHelpers.InMethod();
72// TestHelpers.EnableLogging();
73
74 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
75 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
76
77 InventoryItemBase coaItem
78 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
79
80 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
81
82 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
83
84 CoalescedSceneObjects coa;
85 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
86
87 Assert.That(readResult, Is.True);
88 Assert.That(coa.Count, Is.EqualTo(2));
89
90 List<SceneObjectGroup> coaObjects = coa.Objects;
91 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
92 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
93
94 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
95 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
96 }
97
98 /// <summary>
99 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
100 /// objects.
101 /// </summary>
102 [Test]
103 public void TestLoadIarCreatorAccountPresent()
104 {
105 TestHelpers.InMethod();
106// log4net.Config.XmlConfigurator.Configure();
107
108 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
109
110 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
111 InventoryItemBase foundItem1
112 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
113
114 Assert.That(
115 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
116 "Loaded item non-uuid creator doesn't match original");
117 Assert.That(
118 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
119 "Loaded item uuid creator doesn't match original");
120 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
121 "Loaded item owner doesn't match inventory reciever");
122
123 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
124 string xmlData = Utils.BytesToString(asset1.Data);
125 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
126
127 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
128 }
129
130// /// <summary>
131// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
132// /// an account exists with the same name as the creator, though not the same id.
133// /// </summary>
134// [Test]
135// public void TestLoadIarV0_1SameNameCreator()
136// {
137// TestHelpers.InMethod();
138// TestHelpers.EnableLogging();
139//
140// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
141// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
142//
143// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
144// InventoryItemBase foundItem1
145// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
146//
147// Assert.That(
148// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
149// "Loaded item non-uuid creator doesn't match original");
150// Assert.That(
151// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
152// "Loaded item uuid creator doesn't match original");
153// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
154// "Loaded item owner doesn't match inventory reciever");
155//
156// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
157// string xmlData = Utils.BytesToString(asset1.Data);
158// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
159//
160// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
161// }
162
163 /// <summary>
164 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
165 /// the creator or an account with the creator's name does not exist within the system.
166 /// </summary>
167 [Test]
168 public void TestLoadIarV0_1AbsentCreator()
169 {
170 TestHelpers.InMethod();
171// log4net.Config.XmlConfigurator.Configure();
172
173 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
174 m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
175
176 InventoryItemBase foundItem1
177 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
178
179 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
180 Assert.That(
181 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
182 "Loaded item non-uuid creator doesn't match that of the loading user");
183 Assert.That(
184 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
185 "Loaded item uuid creator doesn't match that of the loading user");
186
187 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
188 string xmlData = Utils.BytesToString(asset1.Data);
189 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
190
191 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
192 }
193 }
194} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
index 06f6e49..5e7e24c 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock;
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 49{
50 [TestFixture] 50 [TestFixture]
51 public class InventoryArchiverTests : InventoryArchiveTestCase 51 public class InventoryArchiveSaveTests : InventoryArchiveTestCase
52 { 52 {
53 protected TestScene m_scene; 53 protected TestScene m_scene;
54 protected InventoryArchiverModule m_archiverModule; 54 protected InventoryArchiverModule m_archiverModule;
@@ -64,36 +64,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
64 m_scene = new SceneHelpers().SetupScene(); 64 m_scene = new SceneHelpers().SetupScene();
65 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); 65 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
66 } 66 }
67
68 [Test]
69 public void TestLoadCoalesecedItem()
70 {
71 TestHelpers.InMethod();
72// TestHelpers.EnableLogging();
73
74 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
75 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
76
77 InventoryItemBase coaItem
78 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
79
80 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
81
82 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
83
84 CoalescedSceneObjects coa;
85 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
86
87 Assert.That(readResult, Is.True);
88 Assert.That(coa.Count, Is.EqualTo(2));
89
90 List<SceneObjectGroup> coaObjects = coa.Objects;
91 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
92 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
93
94 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
95 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
96 }
97 67
98 /// <summary> 68 /// <summary>
99 /// Test that the IAR has the required files in the right order. 69 /// Test that the IAR has the required files in the right order.
@@ -121,6 +91,139 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
121 91
122 Assert.That(iarr.ControlFileLoaded, Is.True); 92 Assert.That(iarr.ControlFileLoaded, Is.True);
123 } 93 }
94
95 [Test]
96 public void TestSaveRootFolderToIar()
97 {
98 TestHelpers.InMethod();
99// TestHelpers.EnableLogging();
100
101 string userFirstName = "Jock";
102 string userLastName = "Stirrup";
103 string userPassword = "troll";
104 UUID userId = TestHelpers.ParseTail(0x20);
105
106 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
107
108 MemoryStream archiveWriteStream = new MemoryStream();
109 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
110
111 mre.Reset();
112 m_archiverModule.ArchiveInventory(
113 Guid.NewGuid(), userFirstName, userLastName, "/", userPassword, archiveWriteStream);
114 mre.WaitOne(60000, false);
115
116 // Test created iar
117 byte[] archive = archiveWriteStream.ToArray();
118 MemoryStream archiveReadStream = new MemoryStream(archive);
119 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
120
121// InventoryArchiveUtils.
122 bool gotObjectsFolder = false;
123
124 string objectsFolderName
125 = string.Format(
126 "{0}{1}",
127 ArchiveConstants.INVENTORY_PATH,
128 InventoryArchiveWriteRequest.CreateArchiveFolderName(
129 UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects")));
130
131 string filePath;
132 TarArchiveReader.TarEntryType tarEntryType;
133
134 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
135 {
136// Console.WriteLine("Got {0}", filePath);
137
138 // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory()
139 // XXX: But really we need to stop all that stuff being created in tests or check for such folders
140 // more thoroughly
141 if (filePath == objectsFolderName)
142 gotObjectsFolder = true;
143 }
144
145 Assert.That(gotObjectsFolder, Is.True);
146 }
147
148 [Test]
149 public void TestSaveNonRootFolderToIar()
150 {
151 TestHelpers.InMethod();
152// TestHelpers.EnableLogging();
153
154 string userFirstName = "Jock";
155 string userLastName = "Stirrup";
156 string userPassword = "troll";
157 UUID userId = TestHelpers.ParseTail(0x20);
158
159 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
160
161 // Create base folder
162 InventoryFolderBase f1
163 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true);
164
165 // Create item1
166 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5);
167 InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1");
168
169 // Create embedded folder
170 InventoryFolderBase f1_1
171 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true);
172
173 // Create embedded item
174 SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6);
175 InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1");
176
177 MemoryStream archiveWriteStream = new MemoryStream();
178 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
179
180 mre.Reset();
181 m_archiverModule.ArchiveInventory(
182 Guid.NewGuid(), userFirstName, userLastName, "f1", userPassword, archiveWriteStream);
183 mre.WaitOne(60000, false);
184
185 // Test created iar
186 byte[] archive = archiveWriteStream.ToArray();
187 MemoryStream archiveReadStream = new MemoryStream(archive);
188 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
189
190// InventoryArchiveUtils.
191 bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false;
192
193 string f1FileName
194 = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1));
195 string f1_1FileName
196 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1));
197 string so1FileName
198 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1));
199 string so2FileName
200 = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2));
201
202 string filePath;
203 TarArchiveReader.TarEntryType tarEntryType;
204
205 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
206 {
207// Console.WriteLine("Got {0}", filePath);
208
209 if (filePath == f1FileName)
210 gotf1 = true;
211 else if (filePath == f1_1FileName)
212 gotf1_1 = true;
213 else if (filePath == so1FileName)
214 gotso1 = true;
215 else if (filePath == so2FileName)
216 gotso2 = true;
217 }
218
219// Assert.That(gotControlFile, Is.True, "No control file in archive");
220 Assert.That(gotf1, Is.True);
221 Assert.That(gotf1_1, Is.True);
222 Assert.That(gotso1, Is.True);
223 Assert.That(gotso2, Is.True);
224
225 // TODO: Test presence of more files and contents of files.
226 }
124 227
125 /// <summary> 228 /// <summary>
126 /// Test saving a single inventory item to an IAR 229 /// Test saving a single inventory item to an IAR
@@ -155,7 +258,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
155 item1.AssetID = asset1.FullID; 258 item1.AssetID = asset1.FullID;
156 item1.ID = item1Id; 259 item1.ID = item1Id;
157 InventoryFolderBase objsFolder 260 InventoryFolderBase objsFolder
158 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 261 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
159 item1.Folder = objsFolder.ID; 262 item1.Folder = objsFolder.ID;
160 m_scene.AddInventoryItem(item1); 263 m_scene.AddInventoryItem(item1);
161 264
@@ -250,7 +353,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
250 item1.AssetID = asset1.FullID; 353 item1.AssetID = asset1.FullID;
251 item1.ID = item1Id; 354 item1.ID = item1Id;
252 InventoryFolderBase objsFolder 355 InventoryFolderBase objsFolder
253 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 356 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
254 item1.Folder = objsFolder.ID; 357 item1.Folder = objsFolder.ID;
255 m_scene.AddInventoryItem(item1); 358 m_scene.AddInventoryItem(item1);
256 359
@@ -317,101 +420,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
317 420
318 // TODO: Test presence of more files and contents of files. 421 // TODO: Test presence of more files and contents of files.
319 } 422 }
320
321 /// <summary>
322 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
323 /// objects.
324 /// </summary>
325 [Test]
326 public void TestLoadIarCreatorAccountPresent()
327 {
328 TestHelpers.InMethod();
329// log4net.Config.XmlConfigurator.Configure();
330
331 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
332
333 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
334 InventoryItemBase foundItem1
335 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
336
337 Assert.That(
338 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
339 "Loaded item non-uuid creator doesn't match original");
340 Assert.That(
341 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
342 "Loaded item uuid creator doesn't match original");
343 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
344 "Loaded item owner doesn't match inventory reciever");
345
346 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
347 string xmlData = Utils.BytesToString(asset1.Data);
348 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
349
350 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
351 }
352
353// /// <summary>
354// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
355// /// an account exists with the same name as the creator, though not the same id.
356// /// </summary>
357// [Test]
358// public void TestLoadIarV0_1SameNameCreator()
359// {
360// TestHelpers.InMethod();
361// TestHelpers.EnableLogging();
362//
363// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
364// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
365//
366// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
367// InventoryItemBase foundItem1
368// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
369//
370// Assert.That(
371// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
372// "Loaded item non-uuid creator doesn't match original");
373// Assert.That(
374// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
375// "Loaded item uuid creator doesn't match original");
376// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
377// "Loaded item owner doesn't match inventory reciever");
378//
379// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
380// string xmlData = Utils.BytesToString(asset1.Data);
381// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
382//
383// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
384// }
385
386 /// <summary>
387 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
388 /// the creator or an account with the creator's name does not exist within the system.
389 /// </summary>
390 [Test]
391 public void TestLoadIarV0_1AbsentCreator()
392 {
393 TestHelpers.InMethod();
394// log4net.Config.XmlConfigurator.Configure();
395
396 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
397 m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
398
399 InventoryItemBase foundItem1
400 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
401
402 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
403 Assert.That(
404 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
405 "Loaded item non-uuid creator doesn't match that of the loading user");
406 Assert.That(
407 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
408 "Loaded item uuid creator doesn't match that of the loading user");
409
410 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
411 string xmlData = Utils.BytesToString(asset1.Data);
412 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
413
414 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
415 }
416 } 423 }
417} \ No newline at end of file 424} \ No newline at end of file
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/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
index 232a4fe..a34f2d2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
@@ -65,7 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
65 { 65 {
66 m_Enabled = true; 66 m_Enabled = true;
67 67
68 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", string.Empty); 68 m_ThisGridURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
69 new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty);
70 // Legacy. Remove soon!
71 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL);
69 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); 72 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name);
70 } 73 }
71 } 74 }
@@ -151,7 +154,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
151 154
152 void OnIncomingInstantMessage(GridInstantMessage im) 155 void OnIncomingInstantMessage(GridInstantMessage im)
153 { 156 {
154 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) 157 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport
158 || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport)
155 { 159 {
156 UUID sessionID = new UUID(im.imSessionID); 160 UUID sessionID = new UUID(im.imSessionID);
157 161
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index f3adb95..0c64f19 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
165 (uint)presence.AbsolutePosition.Y, 165 (uint)presence.AbsolutePosition.Y,
166 (uint)presence.AbsolutePosition.Z + 2); 166 (uint)presence.AbsolutePosition.Z + 2);
167 167
168 m_log.DebugFormat("[LURE]: TP invite with message {0}", message); 168 m_log.DebugFormat("TP invite with message {0}, type {1}", message, lureType);
169 169
170 GridInstantMessage m; 170 GridInstantMessage m;
171 171
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 7f30e5a..2eb9bfb 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Framework
55 /// <summary> 55 /// <summary>
56 /// Each agent has its own capabilities handler. 56 /// Each agent has its own capabilities handler.
57 /// </summary> 57 /// </summary>
58 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>(); 58 protected Dictionary<uint, Caps> m_capsObjects = new Dictionary<uint, Caps>();
59 59
60 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); 60 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>();
61 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds 61 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds
@@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Framework
100 get { return null; } 100 get { return null; }
101 } 101 }
102 102
103 public void CreateCaps(UUID agentId) 103 public void CreateCaps(UUID agentId, uint circuitCode)
104 { 104 {
105 int flags = m_scene.GetUserFlags(agentId); 105 int flags = m_scene.GetUserFlags(agentId);
106 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) 106 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags))
@@ -108,9 +108,9 @@ namespace OpenSim.Region.CoreModules.Framework
108 108
109 String capsObjectPath = GetCapsPath(agentId); 109 String capsObjectPath = GetCapsPath(agentId);
110 110
111 if (m_capsObjects.ContainsKey(agentId)) 111 if (m_capsObjects.ContainsKey(circuitCode))
112 { 112 {
113 Caps oldCaps = m_capsObjects[agentId]; 113 Caps oldCaps = m_capsObjects[circuitCode];
114 114
115 m_log.DebugFormat( 115 m_log.DebugFormat(
116 "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", 116 "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ",
@@ -125,12 +125,12 @@ namespace OpenSim.Region.CoreModules.Framework
125 (MainServer.Instance == null) ? 0: MainServer.Instance.Port, 125 (MainServer.Instance == null) ? 0: MainServer.Instance.Port,
126 capsObjectPath, agentId, m_scene.RegionInfo.RegionName); 126 capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
127 127
128 m_capsObjects[agentId] = caps; 128 m_capsObjects[circuitCode] = caps;
129 129
130 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); 130 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps);
131 } 131 }
132 132
133 public void RemoveCaps(UUID agentId) 133 public void RemoveCaps(UUID agentId, uint circuitCode)
134 { 134 {
135 if (childrenSeeds.ContainsKey(agentId)) 135 if (childrenSeeds.ContainsKey(agentId))
136 { 136 {
@@ -139,11 +139,11 @@ namespace OpenSim.Region.CoreModules.Framework
139 139
140 lock (m_capsObjects) 140 lock (m_capsObjects)
141 { 141 {
142 if (m_capsObjects.ContainsKey(agentId)) 142 if (m_capsObjects.ContainsKey(circuitCode))
143 { 143 {
144 m_capsObjects[agentId].DeregisterHandlers(); 144 m_capsObjects[circuitCode].DeregisterHandlers();
145 m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); 145 m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]);
146 m_capsObjects.Remove(agentId); 146 m_capsObjects.Remove(circuitCode);
147 } 147 }
148 else 148 else
149 { 149 {
@@ -154,19 +154,30 @@ namespace OpenSim.Region.CoreModules.Framework
154 } 154 }
155 } 155 }
156 156
157 public Caps GetCapsForUser(UUID agentId) 157 public Caps GetCapsForUser(uint circuitCode)
158 { 158 {
159 lock (m_capsObjects) 159 lock (m_capsObjects)
160 { 160 {
161 if (m_capsObjects.ContainsKey(agentId)) 161 if (m_capsObjects.ContainsKey(circuitCode))
162 { 162 {
163 return m_capsObjects[agentId]; 163 return m_capsObjects[circuitCode];
164 } 164 }
165 } 165 }
166 166
167 return null; 167 return null;
168 } 168 }
169 169
170 public void ActivateCaps(uint circuitCode)
171 {
172 lock (m_capsObjects)
173 {
174 if (m_capsObjects.ContainsKey(circuitCode))
175 {
176 m_capsObjects[circuitCode].Activate();
177 }
178 }
179 }
180
170 public void SetAgentCapsSeeds(AgentCircuitData agent) 181 public void SetAgentCapsSeeds(AgentCircuitData agent)
171 { 182 {
172 capsPaths[agent.AgentID] = agent.CapsPath; 183 capsPaths[agent.AgentID] = agent.CapsPath;
@@ -237,9 +248,9 @@ namespace OpenSim.Region.CoreModules.Framework
237 StringBuilder caps = new StringBuilder(); 248 StringBuilder caps = new StringBuilder();
238 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); 249 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName);
239 250
240 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects) 251 foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects)
241 { 252 {
242 caps.AppendFormat("** User {0}:\n", kvp.Key); 253 caps.AppendFormat("** Circuit {0}:\n", kvp.Key);
243 254
244 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) 255 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); )
245 { 256 {
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
new file mode 100644
index 0000000..1f1568f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
@@ -0,0 +1,119 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
45 public class DAExampleModule : INonSharedRegionModule
46 {
47// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private static readonly bool ENABLED = false; // enable for testing
50
51 public const string DANamespace = "DAExample Module";
52
53 protected Scene m_scene;
54 protected IDialogModule m_dialogMod;
55
56 public string Name { get { return "DAExample Module"; } }
57 public Type ReplaceableInterface { get { return null; } }
58
59 public void Initialise(IConfigSource source) {}
60
61 public void AddRegion(Scene scene)
62 {
63 if (ENABLED)
64 {
65 m_scene = scene;
66 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
67 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
68 }
69 }
70
71 public void RemoveRegion(Scene scene)
72 {
73 if (ENABLED)
74 {
75 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
76 }
77 }
78
79 public void RegionLoaded(Scene scene) {}
80
81 public void Close()
82 {
83 RemoveRegion(m_scene);
84 }
85
86 protected bool OnSceneGroupMove(UUID groupId, Vector3 delta)
87 {
88 OSDMap attrs = null;
89 SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
90
91 if (sop == null)
92 return true;
93
94 if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs))
95 attrs = new OSDMap();
96
97 OSDInteger newValue;
98
99 // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
100 lock (sop.DynAttrs)
101 {
102 if (!attrs.ContainsKey("moves"))
103 newValue = new OSDInteger(1);
104 else
105 newValue = new OSDInteger(attrs["moves"].AsInteger() + 1);
106
107 attrs["moves"] = newValue;
108
109 sop.DynAttrs[DANamespace] = attrs;
110 }
111
112 sop.ParentGroup.HasGroupChanged = true;
113
114 m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue));
115
116 return true;
117 }
118 }
119} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
new file mode 100644
index 0000000..650aa35
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule
44{
45 /// <summary>
46 /// Example module for experimenting with and demonstrating dynamic object ideas.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")]
49 public class DOExampleModule : INonSharedRegionModule
50 {
51 public class MyObject
52 {
53 public int Moves { get; set; }
54
55 public MyObject(int moves)
56 {
57 Moves = moves;
58 }
59 }
60
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 private static readonly bool ENABLED = false; // enable for testing
64
65 private Scene m_scene;
66 private IDialogModule m_dialogMod;
67
68 public string Name { get { return "DOExample Module"; } }
69 public Type ReplaceableInterface { get { return null; } }
70
71 public void Initialise(IConfigSource source) {}
72
73 public void AddRegion(Scene scene)
74 {
75 if (ENABLED)
76 {
77 m_scene = scene;
78 m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene;
79 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
80 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
81 }
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86 if (ENABLED)
87 {
88 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
89 }
90 }
91
92 public void RegionLoaded(Scene scene) {}
93
94 public void Close()
95 {
96 RemoveRegion(m_scene);
97 }
98
99 private void OnObjectAddedToScene(SceneObjectGroup so)
100 {
101 SceneObjectPart rootPart = so.RootPart;
102
103 OSDMap attrs;
104
105 int movesSoFar = 0;
106
107// Console.WriteLine("Here for {0}", so.Name);
108
109 if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs))
110 {
111 movesSoFar = attrs["moves"].AsInteger();
112
113 m_log.DebugFormat(
114 "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name);
115 }
116
117 rootPart.DynObjs.Add(Name, new MyObject(movesSoFar));
118 }
119
120 private bool OnSceneGroupMove(UUID groupId, Vector3 delta)
121 {
122 SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId);
123
124 if (so == null)
125 return true;
126
127 object rawObj = so.RootPart.DynObjs.Get(Name);
128
129 if (rawObj != null)
130 {
131 MyObject myObj = (MyObject)rawObj;
132
133 m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves));
134 }
135
136 return true;
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index cb09047..b70aeb7 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,6 +33,7 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
@@ -66,6 +67,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
66 /// </summary> 67 /// </summary>
67 public bool WaitForAgentArrivedAtDestination { get; set; } 68 public bool WaitForAgentArrivedAtDestination { get; set; }
68 69
70 /// <summary>
71 /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
72 /// </summary>
73 /// <remarks>
74 /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
75 /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
76 /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
77 /// cancellation consistently suceed.
78 /// </remarks>
79 public bool DisableInterRegionTeleportCancellation { get; set; }
80
81 /// <summary>
82 /// Number of times inter-region teleport was attempted.
83 /// </summary>
84 private Stat m_interRegionTeleportAttempts;
85
86 /// <summary>
87 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
88 /// </summary>
89 private Stat m_interRegionTeleportAborts;
90
91 /// <summary>
92 /// Number of times inter-region teleport was successfully cancelled by the client.
93 /// </summary>
94 private Stat m_interRegionTeleportCancels;
95
96 /// <summary>
97 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
98 /// connect with destination region).
99 /// </summary>
100 /// <remarks>
101 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
102 /// destination simulator is unknown.
103 /// </remarks>
104 private Stat m_interRegionTeleportFailures;
105
69 protected bool m_Enabled = false; 106 protected bool m_Enabled = false;
70 107
71 public Scene Scene { get; private set; } 108 public Scene Scene { get; private set; }
@@ -80,6 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
80 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 117 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
81 118
82 private IEventQueue m_eqModule; 119 private IEventQueue m_eqModule;
120 private IRegionCombinerModule m_regionCombinerModule;
83 121
84 #region ISharedRegionModule 122 #region ISharedRegionModule
85 123
@@ -116,6 +154,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
116 IConfig transferConfig = source.Configs["EntityTransfer"]; 154 IConfig transferConfig = source.Configs["EntityTransfer"];
117 if (transferConfig != null) 155 if (transferConfig != null)
118 { 156 {
157 DisableInterRegionTeleportCancellation
158 = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
159
119 WaitForAgentArrivedAtDestination 160 WaitForAgentArrivedAtDestination
120 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); 161 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
121 162
@@ -142,6 +183,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
142 183
143 Scene = scene; 184 Scene = scene;
144 185
186 m_interRegionTeleportAttempts =
187 new Stat(
188 "InterRegionTeleportAttempts",
189 "Number of inter-region teleports attempted.",
190 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
191 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
192 "",
193 "entitytransfer",
194 Scene.Name,
195 StatType.Push,
196 null,
197 StatVerbosity.Debug);
198
199 m_interRegionTeleportAborts =
200 new Stat(
201 "InterRegionTeleportAborts",
202 "Number of inter-region teleports aborted due to client actions.",
203 "The chief action is simultaneous logout whilst teleporting.",
204 "",
205 "entitytransfer",
206 Scene.Name,
207 StatType.Push,
208 null,
209 StatVerbosity.Debug);
210
211 m_interRegionTeleportCancels =
212 new Stat(
213 "InterRegionTeleportCancels",
214 "Number of inter-region teleports cancelled by the client.",
215 null,
216 "",
217 "entitytransfer",
218 Scene.Name,
219 StatType.Push,
220 null,
221 StatVerbosity.Debug);
222
223 m_interRegionTeleportFailures =
224 new Stat(
225 "InterRegionTeleportFailures",
226 "Number of inter-region teleports that failed due to server/client/network issues.",
227 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
228 "",
229 "entitytransfer",
230 Scene.Name,
231 StatType.Push,
232 null,
233 StatVerbosity.Debug);
234
235 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
236 StatsManager.RegisterStat(m_interRegionTeleportAborts);
237 StatsManager.RegisterStat(m_interRegionTeleportCancels);
238 StatsManager.RegisterStat(m_interRegionTeleportFailures);
239
145 scene.RegisterModuleInterface<IEntityTransferModule>(this); 240 scene.RegisterModuleInterface<IEntityTransferModule>(this);
146 scene.EventManager.OnNewClient += OnNewClient; 241 scene.EventManager.OnNewClient += OnNewClient;
147 } 242 }
@@ -150,12 +245,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
150 { 245 {
151 client.OnTeleportHomeRequest += TriggerTeleportHome; 246 client.OnTeleportHomeRequest += TriggerTeleportHome;
152 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 247 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
153 client.OnTeleportCancel += TeleportCancel; 248
249 if (!DisableInterRegionTeleportCancellation)
250 client.OnTeleportCancel += OnClientCancelTeleport;
251
252 client.OnConnectionClosed += OnConnectionClosed;
154 } 253 }
155 254
156 public virtual void Close() {} 255 public virtual void Close() {}
157 256
158 public virtual void RemoveRegion(Scene scene) {} 257 public virtual void RemoveRegion(Scene scene)
258 {
259 if (m_Enabled)
260 {
261 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
262 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
263 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
264 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
265 }
266 }
159 267
160 public virtual void RegionLoaded(Scene scene) 268 public virtual void RegionLoaded(Scene scene)
161 { 269 {
@@ -163,12 +271,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
163 return; 271 return;
164 272
165 m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); 273 m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
274 m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
166 } 275 }
167 276
168 #endregion 277 #endregion
169 278
170 #region Agent Teleports 279 #region Agent Teleports
171 280
281 private void OnConnectionClosed(IClientAPI client)
282 {
283 if (client.IsLoggingOut)
284 {
285 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting);
286
287 m_log.DebugFormat(
288 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
289 client.Name, Scene.Name);
290 }
291 }
292
293 private void OnClientCancelTeleport(IClientAPI client)
294 {
295 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
296
297 m_log.DebugFormat(
298 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
299 }
300
172 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 301 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
173 { 302 {
174 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 303 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -180,13 +309,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
180 if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) 309 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
181 return; 310 return;
182 311
183 // Reset animations; the viewer does that in teleports.
184 sp.Animator.ResetAnimations();
185
186 string destinationRegionName = "(not found)"; 312 string destinationRegionName = "(not found)";
187 313
314 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
315 // of whether the destination region completes the teleport.
316 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
317 {
318 m_log.DebugFormat(
319 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
320 sp.Name, sp.UUID, position, regionHandle);
321
322 return;
323 }
324
188 try 325 try
189 { 326 {
327 // Reset animations; the viewer does that in teleports.
328 sp.Animator.ResetAnimations();
329
190 if (regionHandle == sp.Scene.RegionInfo.RegionHandle) 330 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
191 { 331 {
192 destinationRegionName = sp.Scene.RegionInfo.RegionName; 332 destinationRegionName = sp.Scene.RegionInfo.RegionName;
@@ -195,12 +335,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
195 } 335 }
196 else // Another region possibly in another simulator 336 else // Another region possibly in another simulator
197 { 337 {
198 GridRegion finalDestination; 338 GridRegion finalDestination = null;
199 TeleportAgentToDifferentRegion( 339 try
200 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); 340 {
201 341 TeleportAgentToDifferentRegion(
202 if (finalDestination != null) 342 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
203 destinationRegionName = finalDestination.RegionName; 343 }
344 finally
345 {
346 if (finalDestination != null)
347 destinationRegionName = finalDestination.RegionName;
348 }
204 } 349 }
205 } 350 }
206 catch (Exception e) 351 catch (Exception e)
@@ -210,11 +355,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
210 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, 355 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
211 e.Message, e.StackTrace); 356 e.Message, e.StackTrace);
212 357
213 // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
214 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
215
216 sp.ControllingClient.SendTeleportFailed("Internal error"); 358 sp.ControllingClient.SendTeleportFailed("Internal error");
217 } 359 }
360 finally
361 {
362 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
363 }
218 } 364 }
219 365
220 /// <summary> 366 /// <summary>
@@ -230,23 +376,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
230 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", 376 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
231 sp.Name, position, sp.Scene.RegionInfo.RegionName); 377 sp.Name, position, sp.Scene.RegionInfo.RegionName);
232 378
233 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
234 {
235 m_log.DebugFormat(
236 "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
237 sp.Name, sp.UUID, position);
238
239 return;
240 }
241
242 // Teleport within the same region 379 // Teleport within the same region
243 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 380 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0)
244 { 381 {
245 Vector3 emergencyPos = new Vector3(128, 128, 128); 382 Vector3 emergencyPos = new Vector3(128, 128, 128);
246 383
247 m_log.WarnFormat( 384 m_log.WarnFormat(
248 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", 385 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
249 position, sp.Name, sp.UUID, emergencyPos); 386 position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
250 387
251 position = emergencyPos; 388 position = emergencyPos;
252 } 389 }
@@ -287,7 +424,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
287 } 424 }
288 425
289 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 426 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
290 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
291 } 427 }
292 428
293 /// <summary> 429 /// <summary>
@@ -341,7 +477,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
341 // 477 //
342 // This is it 478 // This is it
343 // 479 //
344 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); 480 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
345 // 481 //
346 // 482 //
347 // 483 //
@@ -396,27 +532,54 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
396 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; 532 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
397 } 533 }
398 534
535 /// <summary>
536 /// Wraps DoTeleportInternal() and manages the transfer state.
537 /// </summary>
399 public void DoTeleport( 538 public void DoTeleport(
400 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 539 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
401 Vector3 position, Vector3 lookAt, uint teleportFlags) 540 Vector3 position, Vector3 lookAt, uint teleportFlags)
402 { 541 {
403 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection 542 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
404 // of whether the destination region completes the teleport. 543 // of whether the destination region completes the teleport.
405 m_entityTransferStateMachine.SetInTransit(sp.UUID); 544 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
406// if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) 545 {
407// { 546 m_log.DebugFormat(
408// m_log.DebugFormat( 547 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
409// "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", 548 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
410// sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
411//
412// return;
413// }
414 549
415 if (reg == null || finalDestination == null) 550 return;
551 }
552
553 try
554 {
555 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
556 }
557 catch (Exception e)
558 {
559 m_log.ErrorFormat(
560 "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
561 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
562 e.Message, e.StackTrace);
563
564 sp.ControllingClient.SendTeleportFailed("Internal error");
565 }
566 finally
416 { 567 {
417 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
418 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 568 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
569 }
570 }
419 571
572 /// <summary>
573 /// Teleports the agent to another region.
574 /// This method doesn't manage the transfer state; the caller must do that.
575 /// </summary>
576 private void DoTeleportInternal(
577 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
578 Vector3 position, Vector3 lookAt, uint teleportFlags)
579 {
580 if (reg == null || finalDestination == null)
581 {
582 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
420 return; 583 return;
421 } 584 }
422 585
@@ -436,8 +599,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
436 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, 599 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
437 MaxTransferDistance)); 600 MaxTransferDistance));
438 601
439 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
440
441 return; 602 return;
442 } 603 }
443 604
@@ -455,7 +616,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
455 if (endPoint == null || endPoint.Address == null) 616 if (endPoint == null || endPoint.Address == null)
456 { 617 {
457 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 618 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
458 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
459 619
460 return; 620 return;
461 } 621 }
@@ -465,19 +625,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
465 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 625 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
466 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 626 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName);
467 627
468// if (!sp.ValidateAttachments())
469// {
470// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
471// return;
472// }
473
474 string reason; 628 string reason;
475 string version; 629 string version;
476 if (!Scene.SimulationService.QueryAccess( 630 if (!Scene.SimulationService.QueryAccess(
477 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 631 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
478 { 632 {
479 sp.ControllingClient.SendTeleportFailed(reason); 633 sp.ControllingClient.SendTeleportFailed(reason);
480 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
481 634
482 m_log.DebugFormat( 635 m_log.DebugFormat(
483 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 636 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
@@ -486,6 +639,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
486 return; 639 return;
487 } 640 }
488 641
642 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
643 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
644 // as server attempts.
645 m_interRegionTeleportAttempts.Value++;
646
489 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 647 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
490 648
491 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 649 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
@@ -495,6 +653,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
495 else if (sp.Flying) 653 else if (sp.Flying)
496 teleportFlags |= (uint)TeleportFlags.IsFlying; 654 teleportFlags |= (uint)TeleportFlags.IsFlying;
497 655
656 if (DisableInterRegionTeleportCancellation)
657 teleportFlags |= (uint)TeleportFlags.DisableCancel;
658
498 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to 659 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
499 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). 660 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
500 sp.ControllingClient.SendTeleportStart(teleportFlags); 661 sp.ControllingClient.SendTeleportStart(teleportFlags);
@@ -531,11 +692,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
531 } 692 }
532 693
533 // Let's create an agent there if one doesn't exist yet. 694 // Let's create an agent there if one doesn't exist yet.
695 // NOTE: logout will always be false for a non-HG teleport.
534 bool logout = false; 696 bool logout = false;
535 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 697 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
536 { 698 {
699 m_interRegionTeleportFailures.Value++;
700
537 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 701 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
538 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
539 702
540 m_log.DebugFormat( 703 m_log.DebugFormat(
541 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 704 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
@@ -544,6 +707,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
544 return; 707 return;
545 } 708 }
546 709
710 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
711 {
712 m_interRegionTeleportCancels.Value++;
713
714 m_log.DebugFormat(
715 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
716 sp.Name, finalDestination.RegionName, sp.Scene.Name);
717
718 return;
719 }
720 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
721 {
722 m_interRegionTeleportAborts.Value++;
723
724 m_log.DebugFormat(
725 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
726 sp.Name, finalDestination.RegionName, sp.Scene.Name);
727
728 return;
729 }
730
547 // Past this point we have to attempt clean up if the teleport fails, so update transfer state. 731 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
548 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 732 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
549 733
@@ -553,6 +737,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
553 IClientIPEndpoint ipepClient; 737 IClientIPEndpoint ipepClient;
554 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 738 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
555 { 739 {
740 m_log.DebugFormat(
741 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
742 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
743
556 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 744 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
557 #region IP Translation for NAT 745 #region IP Translation for NAT
558 // Uses ipepClient above 746 // Uses ipepClient above
@@ -565,11 +753,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
565 753
566 if (m_eqModule != null) 754 if (m_eqModule != null)
567 { 755 {
756 // The EnableSimulator message makes the client establish a connection with the destination
757 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
758 // correct circuit code.
568 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 759 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID);
569 760
570 // ES makes the client send a UseCircuitCode message to the destination, 761 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
571 // which triggers a bunch of things there. 762 // simulator to confirm that it has established communication with the viewer.
572 // So let's wait
573 Thread.Sleep(200); 763 Thread.Sleep(200);
574 764
575 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 765 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
@@ -580,6 +770,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
580 } 770 }
581 else 771 else
582 { 772 {
773 // XXX: This is a little misleading since we're information the client of its avatar destination,
774 // which may or may not be a neighbour region of the source region. This path is probably little
775 // used anyway (with EQ being the one used). But it is currently being used for test code.
583 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 776 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
584 } 777 }
585 } 778 }
@@ -597,23 +790,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
597 790
598 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); 791 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
599 792
793 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
794 // establish th econnection to the destination which makes it return true.
795 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
796 {
797 m_interRegionTeleportAborts.Value++;
798
799 m_log.DebugFormat(
800 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
801 sp.Name, finalDestination.RegionName, sp.Scene.Name);
802
803 return;
804 }
805
806 // A common teleport failure occurs when we can send CreateAgent to the
807 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
808 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
809 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
600 if (!UpdateAgent(reg, finalDestination, agent, sp)) 810 if (!UpdateAgent(reg, finalDestination, agent, sp))
601 { 811 {
602 // Region doesn't take it 812 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
813 {
814 m_interRegionTeleportAborts.Value++;
815
816 m_log.DebugFormat(
817 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
818 sp.Name, finalDestination.RegionName, sp.Scene.Name);
819
820 return;
821 }
822
603 m_log.WarnFormat( 823 m_log.WarnFormat(
604 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 824 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
605 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 825 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
606 826
607 Fail(sp, finalDestination, logout); 827 Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established.");
608 return; 828 return;
609 } 829 }
610 830
611 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 831 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
832 {
833 m_interRegionTeleportCancels.Value++;
834
835 m_log.DebugFormat(
836 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
837 sp.Name, finalDestination.RegionName, sp.Scene.Name);
838
839 CleanupFailedInterRegionTeleport(sp, finalDestination);
840
841 return;
842 }
612 843
613 m_log.DebugFormat( 844 m_log.DebugFormat(
614 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 845 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
615 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 846 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
616 847
848 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
849 // where that neighbour simulator could otherwise request a child agent create on the source which then
850 // closes our existing agent which is still signalled as root.
851 sp.IsChildAgent = true;
852
617 if (m_eqModule != null) 853 if (m_eqModule != null)
618 { 854 {
619 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 855 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
@@ -624,19 +860,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
624 teleportFlags, capsPath); 860 teleportFlags, capsPath);
625 } 861 }
626 862
627 // Let's set this to true tentatively. This does not trigger OnChildAgent
628 sp.IsChildAgent = true;
629
630 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 863 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
631 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 864 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
632 // that the client contacted the destination before we close things here. 865 // that the client contacted the destination before we close things here.
633 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 866 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
634 { 867 {
868 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
869 {
870 m_interRegionTeleportAborts.Value++;
871
872 m_log.DebugFormat(
873 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
874 sp.Name, finalDestination.RegionName, sp.Scene.Name);
875
876 return;
877 }
878
635 m_log.WarnFormat( 879 m_log.WarnFormat(
636 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 880 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
637 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 881 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
638 882
639 Fail(sp, finalDestination, logout); 883 Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
884
640 return; 885 return;
641 } 886 }
642 887
@@ -659,8 +904,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
659 // Now let's make it officially a child agent 904 // Now let's make it officially a child agent
660 sp.MakeChildAgent(); 905 sp.MakeChildAgent();
661 906
662// sp.Scene.CleanDroppedAttachments();
663
664 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 907 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
665 908
666 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 909 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
@@ -680,27 +923,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
680 // now we have a child agent in this region. 923 // now we have a child agent in this region.
681 sp.Reset(); 924 sp.Reset();
682 } 925 }
683
684 // Commented pending deletion since this method no longer appears to do anything at all
685// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
686// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
687// {
688// m_log.DebugFormat(
689// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
690// sp.UUID);
691// }
692
693 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
694 } 926 }
695 927
696 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 928 /// <summary>
929 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
930 /// </summary>
931 /// <remarks>
932 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
933 /// up until we send the TeleportFinish event quene event to the viewer.
934 /// <remarks>
935 /// <param name='sp'> </param>
936 /// <param name='finalDestination'></param>
937 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
697 { 938 {
698 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 939 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
699 940
700 // Client never contacted destination. Let's restore everything back
701 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
702
703 // Fail. Reset it back
704 sp.IsChildAgent = false; 941 sp.IsChildAgent = false;
705 ReInstantiateScripts(sp); 942 ReInstantiateScripts(sp);
706 943
@@ -708,10 +945,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
708 945
709 // Finally, kill the agent we just created at the destination. 946 // Finally, kill the agent we just created at the destination.
710 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); 947 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
948 }
711 949
712 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 950 /// <summary>
951 /// Signal that the inter-region teleport failed and perform cleanup.
952 /// </summary>
953 /// <param name='sp'></param>
954 /// <param name='finalDestination'></param>
955 /// <param name='logout'></param>
956 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
957 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason)
958 {
959 CleanupFailedInterRegionTeleport(sp, finalDestination);
960
961 m_interRegionTeleportFailures.Value++;
713 962
714 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 963 sp.ControllingClient.SendTeleportFailed(
964 string.Format(
965 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
966
967 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
715 } 968 }
716 969
717 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 970 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
@@ -762,7 +1015,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
762 1015
763 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1016 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
764 { 1017 {
765 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1018 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1019 {
1020 Vector2 swCorner, neCorner;
1021 GetMegaregionViewRange(out swCorner, out neCorner);
1022
1023 m_log.DebugFormat(
1024 "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1025 Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1026
1027 return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1028 }
1029 else
1030 {
1031 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1032 }
766 } 1033 }
767 1034
768 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) 1035 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@@ -866,6 +1133,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
866 { 1133 {
867 version = String.Empty; 1134 version = String.Empty;
868 newpos = new Vector3(pos.X, pos.Y, pos.Z); 1135 newpos = new Vector3(pos.X, pos.Y, pos.Z);
1136
1137// m_log.DebugFormat(
1138// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
1139
869 uint neighbourx = scene.RegionInfo.RegionLocX; 1140 uint neighbourx = scene.RegionInfo.RegionLocX;
870 uint neighboury = scene.RegionInfo.RegionLocY; 1141 uint neighboury = scene.RegionInfo.RegionLocY;
871 const float boundaryDistance = 1.7f; 1142 const float boundaryDistance = 1.7f;
@@ -995,11 +1266,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
995 return neighbourRegion; 1266 return neighbourRegion;
996 } 1267 }
997 1268
998 private void TeleportCancel(IClientAPI remoteClient)
999 {
1000 m_entityTransferStateMachine.ResetFromTransit(remoteClient.AgentId);
1001 }
1002
1003 public bool Cross(ScenePresence agent, bool isFlying) 1269 public bool Cross(ScenePresence agent, bool isFlying)
1004 { 1270 {
1005 uint x; 1271 uint x;
@@ -1023,16 +1289,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1023 } 1289 }
1024 1290
1025 1291
1026 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, 1292 public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
1027 Vector3 position, 1293 Vector3 position,
1028 Scene initiatingScene); 1294 Scene initiatingScene);
1029 1295
1030 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) 1296 private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1031 { 1297 {
1032 1298
1033 // This assumes that we know what our neighbours are. 1299 // This assumes that we know what our neighbours are.
1034 1300
1035 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; 1301 InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1036 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, 1302 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1037 InformClientToInitiateTeleportToLocationCompleted, 1303 InformClientToInitiateTeleportToLocationCompleted,
1038 d); 1304 d);
@@ -1042,7 +1308,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1042 Scene initiatingScene) 1308 Scene initiatingScene)
1043 { 1309 {
1044 Thread.Sleep(10000); 1310 Thread.Sleep(10000);
1045 1311
1312 m_log.DebugFormat(
1313 "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1314 agent.Name, regionX, regionY, position, initiatingScene.Name);
1315
1316 agent.Scene.RequestTeleportLocation(
1317 agent.ControllingClient,
1318 Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize),
1319 position,
1320 agent.Lookat,
1321 (uint)Constants.TeleportFlags.ViaLocation);
1322
1323 /*
1046 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1324 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1047 if (im != null) 1325 if (im != null)
1048 { 1326 {
@@ -1077,12 +1355,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1077 }); 1355 });
1078 1356
1079 } 1357 }
1358 */
1080 } 1359 }
1081 1360
1082 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) 1361 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1083 { 1362 {
1084 InformClientToInitateTeleportToLocationDelegate icon = 1363 InformClientToInitiateTeleportToLocationDelegate icon =
1085 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; 1364 (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1086 icon.EndInvoke(iar); 1365 icon.EndInvoke(iar);
1087 } 1366 }
1088 1367
@@ -1107,10 +1386,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1107 bool isFlying, string version) 1386 bool isFlying, string version)
1108 { 1387 {
1109 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) 1388 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1389 {
1390 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1110 return agent; 1391 return agent;
1392 }
1111 1393
1112 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) 1394 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying))
1395 {
1396 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1113 return agent; 1397 return agent;
1398 }
1114 1399
1115 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version); 1400 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version);
1116 return agent; 1401 return agent;
@@ -1137,9 +1422,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1137 // region doesn't take it 1422 // region doesn't take it
1138 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); 1423 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1139 1424
1425 m_log.WarnFormat(
1426 "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1427 neighbourRegion.RegionName, agent.Name);
1428
1140 ReInstantiateScripts(agent); 1429 ReInstantiateScripts(agent);
1141 agent.AddToPhysicalScene(isFlying); 1430 agent.AddToPhysicalScene(isFlying);
1142 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1143 1431
1144 return false; 1432 return false;
1145 } 1433 }
@@ -1576,6 +1864,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1576 } 1864 }
1577 1865
1578 /// <summary> 1866 /// <summary>
1867 /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
1868 /// </summary>
1869 /// <remarks>Expressed in 256m units</remarks>
1870 /// <param name='swCorner'></param>
1871 /// <param name='neCorner'></param>
1872 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
1873 {
1874 Border[] northBorders = Scene.NorthBorders.ToArray();
1875 Border[] eastBorders = Scene.EastBorders.ToArray();
1876
1877 Vector2 extent = Vector2.Zero;
1878 for (int i = 0; i < eastBorders.Length; i++)
1879 {
1880 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1881 }
1882 for (int i = 0; i < northBorders.Length; i++)
1883 {
1884 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1885 }
1886
1887 // Loss of fraction on purpose
1888 extent.X = ((int)extent.X / (int)Constants.RegionSize);
1889 extent.Y = ((int)extent.Y / (int)Constants.RegionSize);
1890
1891 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
1892 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
1893 neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
1894 neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
1895 }
1896
1897 /// <summary>
1579 /// Return the list of regions that are considered to be neighbours to the given scene. 1898 /// Return the list of regions that are considered to be neighbours to the given scene.
1580 /// </summary> 1899 /// </summary>
1581 /// <param name="pScene"></param> 1900 /// <param name="pScene"></param>
@@ -1587,15 +1906,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1587 Scene pScene = avatar.Scene; 1906 Scene pScene = avatar.Scene;
1588 RegionInfo m_regionInfo = pScene.RegionInfo; 1907 RegionInfo m_regionInfo = pScene.RegionInfo;
1589 1908
1590 Border[] northBorders = pScene.NorthBorders.ToArray();
1591 Border[] southBorders = pScene.SouthBorders.ToArray();
1592 Border[] eastBorders = pScene.EastBorders.ToArray();
1593 Border[] westBorders = pScene.WestBorders.ToArray();
1594
1595 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 1909 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
1596 // clear what should be done with a "far view" given that megaregions already extended the 1910 // clear what should be done with a "far view" given that megaregions already extended the
1597 // view to include everything in the megaregion 1911 // view to include everything in the megaregion
1598 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) 1912 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1599 { 1913 {
1600 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 1914 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance;
1601 1915
@@ -1613,27 +1927,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1613 } 1927 }
1614 else 1928 else
1615 { 1929 {
1616 Vector2 extent = Vector2.Zero; 1930 Vector2 swCorner, neCorner;
1617 for (int i = 0; i < eastBorders.Length; i++) 1931 GetMegaregionViewRange(out swCorner, out neCorner);
1618 {
1619 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1620 }
1621 for (int i = 0; i < northBorders.Length; i++)
1622 {
1623 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1624 }
1625
1626 // Loss of fraction on purpose
1627 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1;
1628 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1;
1629
1630 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize;
1631 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize;
1632 1932
1633 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; 1933 List<GridRegion> neighbours
1634 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; 1934 = pScene.GridService.GetRegionRange(
1935 m_regionInfo.ScopeID,
1936 (int)swCorner.X * (int)Constants.RegionSize,
1937 (int)neCorner.X * (int)Constants.RegionSize,
1938 (int)swCorner.Y * (int)Constants.RegionSize,
1939 (int)neCorner.Y * (int)Constants.RegionSize);
1635 1940
1636 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY);
1637 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 1941 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
1638 1942
1639 return neighbours; 1943 return neighbours;
@@ -2054,7 +2358,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2054 2358
2055 public bool IsInTransit(UUID id) 2359 public bool IsInTransit(UUID id)
2056 { 2360 {
2057 return m_entityTransferStateMachine.IsInTransit(id); 2361 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2058 } 2362 }
2059 2363
2060 protected void ReInstantiateScripts(ScenePresence sp) 2364 protected void ReInstantiateScripts(ScenePresence sp)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index 70dd1bc..e903383 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// ReceivedAtDestination => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp || Aborting
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
58 /// 60 ///
59 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
60 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 66 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 67 Transferring, // The agent is in the process of being transferred to a destination
66 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 68 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
67 CleaningUp // The agent is being changed to child/removed after a transfer 69 CleaningUp, // The agent is being changed to child/removed after a transfer
70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
68 } 72 }
69 73
70 /// <summary> 74 /// <summary>
@@ -115,42 +119,114 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 119 /// <param name='newState'></param>
116 /// <returns></returns> 120 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 121 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 122 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 123 {
124 bool transitionOkay = false;
125
126 // We don't want to throw an exception on cancel since this can come it at any time.
127 bool failIfNotOkay = true;
128
129 // Should be a failure message if failure is not okay.
130 string failureMessage = null;
131
132 AgentTransferState? oldState = null;
133
120 lock (m_agentsInTransit) 134 lock (m_agentsInTransit)
121 { 135 {
122 // Illegal to try and update an agent that's not actually in transit. 136 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 137 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 138 {
125 string.Format( 139 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
126 "Agent with ID {0} is not registered as in transit in {1}", 140 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 141 "Agent with ID {0} is not registered as in transit in {1}",
128 142 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 143 else
144 failIfNotOkay = false;
145 }
146 else
147 {
148 oldState = m_agentsInTransit[id];
130 149
131 bool transitionOkay = false; 150 if (newState == AgentTransferState.Aborting)
151 {
152 transitionOkay = true;
153 }
154 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
155 {
156 transitionOkay = true;
157 }
158 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
159 {
160 transitionOkay = true;
161 }
162 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
163 {
164 transitionOkay = true;
165 }
166 else
167 {
168 if (newState == AgentTransferState.Cancelling
169 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
170 {
171 transitionOkay = true;
172 }
173 else
174 {
175 failIfNotOkay = false;
176 }
177 }
132 178
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 179 if (!transitionOkay)
134 transitionOkay = true; 180 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 181 = string.Format(
136 transitionOkay = true; 182 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 183 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 184 }
139 185
140 if (transitionOkay) 186 if (transitionOkay)
187 {
141 m_agentsInTransit[id] = newState; 188 m_agentsInTransit[id] = newState;
142 else 189
143 throw new Exception( 190// m_log.DebugFormat(
144 string.Format( 191// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 192// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 193 }
194 else if (failIfNotOkay)
195 {
196 throw new Exception(failureMessage);
197 }
198// else
199// {
200// if (oldState != null)
201// m_log.DebugFormat(
202// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
203// id, oldState, newState, m_mod.Scene.Name);
204// else
205// m_log.DebugFormat(
206// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
207// id, newState, m_mod.Scene.Name);
208// }
147 } 209 }
210
211 return transitionOkay;
148 } 212 }
149 213
150 internal bool IsInTransit(UUID id) 214 /// <summary>
215 /// Gets the current agent transfer state.
216 /// </summary>
217 /// <returns>Null if the agent is not in transit</returns>
218 /// <param name='id'>
219 /// Identifier.
220 /// </param>
221 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 222 {
152 lock (m_agentsInTransit) 223 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 224 {
225 if (!m_agentsInTransit.ContainsKey(id))
226 return null;
227 else
228 return m_agentsInTransit[id];
229 }
154 } 230 }
155 231
156 /// <summary> 232 /// <summary>
@@ -203,14 +279,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 279
204 lock (m_agentsInTransit) 280 lock (m_agentsInTransit)
205 { 281 {
206 if (!IsInTransit(id)) 282 AgentTransferState? currentState = GetAgentTransferState(id);
283
284 if (currentState == null)
207 throw new Exception( 285 throw new Exception(
208 string.Format( 286 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 287 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
210 id, m_mod.Scene.RegionInfo.RegionName)); 288 id, m_mod.Scene.RegionInfo.RegionName));
211 289
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 290 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 291 throw new Exception(
216 string.Format( 292 string.Format(
@@ -222,8 +298,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
222 298
223 // There should be no race condition here since no other code should be removing the agent transfer or 299 // There should be no race condition here since no other code should be removing the agent transfer or
224 // changing the state to another other than Transferring => ReceivedAtDestination. 300 // changing the state to another other than Transferring => ReceivedAtDestination.
225 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 301
302 while (count-- > 0)
226 { 303 {
304 lock (m_agentsInTransit)
305 {
306 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
307 break;
308 }
309
227// m_log.Debug(" >>> Waiting... " + count); 310// m_log.Debug(" >>> Waiting... " + count);
228 Thread.Sleep(100); 311 Thread.Sleep(100);
229 } 312 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index f3a0b01..d372c0e 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
199 199
200 public override void RemoveRegion(Scene scene) 200 public override void RemoveRegion(Scene scene)
201 { 201 {
202 base.AddRegion(scene); 202 base.RemoveRegion(scene);
203 203
204 if (m_Enabled) 204 if (m_Enabled)
205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); 205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
@@ -212,11 +212,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
212 protected override GridRegion GetFinalDestination(GridRegion region) 212 protected override GridRegion GetFinalDestination(GridRegion region)
213 { 213 {
214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); 215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
216 216
217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) 217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
218 { 218 {
219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); 219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
221 if (real_destination != null) 221 if (real_destination != null)
222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); 222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI);
diff --git a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs
index 4004135..b9786ae 100644
--- a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs
+++ b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Command.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using OpenSim.Region.Framework.Interfaces; 30using OpenSim.Region.Framework.Interfaces;
31using OpenMetaverse;
31 32
32namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander 33namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander
33{ 34{
@@ -152,6 +153,9 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander
152 case "Boolean": 153 case "Boolean":
153 m_args[i].ArgumentValue = Boolean.Parse(arg.ToString()); 154 m_args[i].ArgumentValue = Boolean.Parse(arg.ToString());
154 break; 155 break;
156 case "UUID":
157 m_args[i].ArgumentValue = UUID.Parse(arg.ToString());
158 break;
155 default: 159 default:
156 Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name); 160 Console.WriteLine("ERROR: Unknown desired type for argument " + m_args[i].Name + " on command " + m_name);
157 break; 161 break;
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/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index 964efda..b2b628d 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -88,12 +88,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
88 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; 88 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"];
89 if (thisModuleConfig != null) 89 if (thisModuleConfig != null)
90 { 90 {
91 // legacy configuration [obsolete] 91 m_HomeURI = Util.GetConfigVarFromSections<string>(source, "HomeURI",
92 m_HomeURI = thisModuleConfig.GetString("ProfileServerURI", string.Empty); 92 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
93 // preferred 93 m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
94 m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); 94 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
95 // Legacy. Renove soon!
96 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper);
97
95 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); 98 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
96 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
97 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); 99 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
98 } 100 }
99 else 101 else
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 6e5a4a5..5aad7f0 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -47,6 +47,7 @@ using OpenMetaverse;
47using log4net; 47using log4net;
48using Nini.Config; 48using Nini.Config;
49using Mono.Addins; 49using Mono.Addins;
50using PermissionMask = OpenSim.Framework.PermissionMask;
50 51
51namespace OpenSim.Region.CoreModules.Framework.InventoryAccess 52namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
52{ 53{
@@ -398,7 +399,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
398 objectGroup.RootPart.NextOwnerMask &= 399 objectGroup.RootPart.NextOwnerMask &=
399 ((uint)PermissionMask.Copy | 400 ((uint)PermissionMask.Copy |
400 (uint)PermissionMask.Transfer | 401 (uint)PermissionMask.Transfer |
401 (uint)PermissionMask.Modify); 402 (uint)PermissionMask.Modify |
403 (uint)PermissionMask.Export);
402 objectGroup.RootPart.NextOwnerMask |= 404 objectGroup.RootPart.NextOwnerMask |=
403 (uint)PermissionMask.Move; 405 (uint)PermissionMask.Move;
404 406
@@ -506,7 +508,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
506 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, 508 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
507 IClientAPI remoteClient) 509 IClientAPI remoteClient)
508 { 510 {
509 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; 511 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
510 // For the porposes of inventory, an object is modify if the prims 512 // For the porposes of inventory, an object is modify if the prims
511 // are modify. This allows renaming an object that contains no 513 // are modify. This allows renaming an object that contains no
512 // mod items. 514 // mod items.
@@ -555,6 +557,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
555 (uint)PermissionMask.Transfer | 557 (uint)PermissionMask.Transfer |
556 (uint)PermissionMask.Modify | 558 (uint)PermissionMask.Modify |
557 (uint)PermissionMask.Move | 559 (uint)PermissionMask.Move |
560 (uint)PermissionMask.Export |
558 7); // Preserve folded permissions 561 7); // Preserve folded permissions
559 } 562 }
560 563
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index 21d8bd7..ad1a0e1 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();
@@ -107,7 +109,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
107 item1.AssetID = asset1.FullID; 109 item1.AssetID = asset1.FullID;
108 item1.ID = item1Id; 110 item1.ID = item1Id;
109 InventoryFolderBase objsFolder 111 InventoryFolderBase objsFolder
110 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 112 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
111 item1.Folder = objsFolder.ID; 113 item1.Folder = objsFolder.ID;
112 m_scene.AddInventoryItem(item1); 114 m_scene.AddInventoryItem(item1);
113 115
@@ -157,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
157 item1.AssetID = asset1.FullID; 159 item1.AssetID = asset1.FullID;
158 item1.ID = item1Id; 160 item1.ID = item1Id;
159 InventoryFolderBase objsFolder 161 InventoryFolderBase objsFolder
160 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 162 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
161 item1.Folder = objsFolder.ID; 163 item1.Folder = objsFolder.ID;
162 m_scene.AddInventoryItem(item1); 164 m_scene.AddInventoryItem(item1);
163 165
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
index ec22146..d07cff4 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
@@ -43,6 +43,7 @@ using OpenMetaverse;
43using log4net; 43using log4net;
44using Mono.Addins; 44using Mono.Addins;
45using Nini.Config; 45using Nini.Config;
46using PermissionMask = OpenSim.Framework.PermissionMask;
46 47
47namespace OpenSim.Region.CoreModules.Framework.Library 48namespace OpenSim.Region.CoreModules.Framework.Library
48{ 49{
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
index d84460a..64feec1 100644
--- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
@@ -33,6 +33,7 @@ using log4net;
33using Nini.Config; 33using Nini.Config;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Servers; 37using OpenSim.Framework.Servers;
37using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; 38using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts;
38using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; 39using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors;
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
100 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); 101 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage);
101 102
102 AddMonitors(); 103 AddMonitors();
104 RegisterStatsManagerRegionStatistics();
103 } 105 }
104 106
105 public void RemoveRegion(Scene scene) 107 public void RemoveRegion(Scene scene)
@@ -109,6 +111,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
109 111
110 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); 112 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID);
111 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); 113 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName));
114
115 UnRegisterStatsManagerRegionStatistics();
116
112 m_scene = null; 117 m_scene = null;
113 } 118 }
114 119
@@ -399,6 +404,45 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
399 { 404 {
400 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); 405 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")");
401 } 406 }
407
408 private List<Stat> registeredStats = new List<Stat>();
409 private void MakeStat(string pName, string pUnitName, Action<Stat> act)
410 {
411 Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info);
412 StatsManager.RegisterStat(tempStat);
413 registeredStats.Add(tempStat);
414 }
415 private void RegisterStatsManagerRegionStatistics()
416 {
417 MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
418 MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
419 MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
420 MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); });
421 MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); });
422
423 MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; });
424 MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; });
425 MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; });
426 MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; });
427 MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; });
428 MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; });
429 MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; });
430 MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; });
431 MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; });
432 MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; });
433 MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; });
434 MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; });
435 }
436
437 private void UnRegisterStatsManagerRegionStatistics()
438 {
439 foreach (Stat stat in registeredStats)
440 {
441 StatsManager.DeregisterStat(stat);
442 stat.Dispose();
443 }
444 registeredStats.Clear();
445 }
402 446
403 } 447 }
404} 448} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index fb74cc6..f3436d1 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
57 try 57 try
58 { 58 {
59 IConfig statConfig = source.Configs["Statistics.Binary"]; 59 IConfig statConfig = source.Configs["Statistics.Binary"];
60 if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) 60 if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
61 { 61 {
62 if (statConfig.Contains("collect_region_stats")) 62 if (statConfig.Contains("collect_region_stats"))
63 { 63 {
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
index fd8d5e3..2fe9026 100755
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
52 private TimeSpan m_logFileLife; 52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime; 53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object(); 54 private Object m_logFileWriteLock = new Object();
55 private bool m_flushWrite;
55 56
56 // set externally when debugging. If let 'null', this does not write any error messages. 57 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null; 58 public ILog ErrorLogger = null;
@@ -73,7 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> 74 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> 75 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> 76 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime) 77 /// <param name="flushWrite">Whether to do a flush after every log write. Best left off but
78 /// if one is looking for a crash, this is a good thing to turn on.</param>
79 public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite)
77 { 80 {
78 m_logDirectory = dir == null ? "." : dir; 81 m_logDirectory = dir == null ? "." : dir;
79 82
@@ -86,8 +89,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); 89 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife; 90 m_logFileEndTime = DateTime.Now + m_logFileLife;
88 91
92 m_flushWrite = flushWrite;
93
89 Enabled = true; 94 Enabled = true;
90 } 95 }
96 // Constructor that assumes flushWrite is off.
97 public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false)
98 {
99 }
91 100
92 public void Dispose() 101 public void Dispose()
93 { 102 {
@@ -127,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
127 { 136 {
128 lock (m_logFileWriteLock) 137 lock (m_logFileWriteLock)
129 { 138 {
130 DateTime now = DateTime.Now; 139 DateTime now = DateTime.UtcNow;
131 if (m_logFile == null || now > m_logFileEndTime) 140 if (m_logFile == null || now > m_logFileEndTime)
132 { 141 {
133 if (m_logFile != null) 142 if (m_logFile != null)
@@ -153,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
153 buff.Append(line); 162 buff.Append(line);
154 buff.Append("\r\n"); 163 buff.Append("\r\n");
155 m_logFile.Write(buff.ToString()); 164 m_logFile.Write(buff.ToString());
165 if (m_flushWrite)
166 m_logFile.Flush();
156 } 167 }
157 } 168 }
158 } 169 }
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/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
index ec94420..7b11658 100644
--- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
@@ -52,8 +52,8 @@ namespace OpenSim.Region.CoreModules.Hypergrid
52 52
53 public override void Initialise(IConfigSource config) 53 public override void Initialise(IConfigSource config)
54 { 54 {
55 IConfig startupConfig = config.Configs["Startup"]; 55 if (Util.GetConfigVarFromSections<string>(
56 if (startupConfig.GetString("WorldMapModule", "WorldMap") == "HGWorldMap") 56 config, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap")
57 m_Enabled = true; 57 m_Enabled = true;
58 } 58 }
59 59
diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
index 5a8c4a2..bfe0383 100644
--- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
@@ -30,8 +30,8 @@ using Mono.Addins;
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.7.6.*")]
34[assembly: AssemblyFileVersion("1.0.0.0")] 34
35 35
36[assembly: Addin("OpenSim.Region.CoreModules", "0.1")] 36[assembly: Addin("OpenSim.Region.CoreModules", "0.1")]
37[assembly: AddinDependency("OpenSim", "0.5")] 37[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index 0276267..2b13a8b 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -189,6 +189,45 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
189 case (int)HttpRequestConstants.HTTP_VERIFY_CERT: 189 case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
190 htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); 190 htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
191 break; 191 break;
192
193 case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE:
194
195 // TODO implement me
196 break;
197
198 case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER:
199 //Parameters are in pairs and custom header takes
200 //arguments in pairs so adjust for header marker.
201 ++i;
202
203 //Maximum of 8 headers are allowed based on the
204 //Second Life documentation for llHTTPRequest.
205 for (int count = 1; count <= 8; ++count)
206 {
207 //Not enough parameters remaining for a header?
208 if (parms.Length - i < 2)
209 break;
210
211 //Have we reached the end of the list of headers?
212 //End is marked by a string with a single digit.
213 //We already know we have at least one parameter
214 //so it is safe to do this check at top of loop.
215 if (Char.IsDigit(parms[i][0]))
216 break;
217
218 if (htc.HttpCustomHeaders == null)
219 htc.HttpCustomHeaders = new List<string>();
220
221 htc.HttpCustomHeaders.Add(parms[i]);
222 htc.HttpCustomHeaders.Add(parms[i+1]);
223
224 i += 2;
225 }
226 break;
227
228 case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE:
229 htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0);
230 break;
192 } 231 }
193 } 232 }
194 } 233 }
@@ -353,9 +392,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
353 // public const int HTTP_METHOD = 0; 392 // public const int HTTP_METHOD = 0;
354 // public const int HTTP_MIMETYPE = 1; 393 // public const int HTTP_MIMETYPE = 1;
355 // public const int HTTP_VERIFY_CERT = 3; 394 // public const int HTTP_VERIFY_CERT = 3;
395 // public const int HTTP_VERBOSE_THROTTLE = 4;
396 // public const int HTTP_CUSTOM_HEADER = 5;
397 // public const int HTTP_PRAGMA_NO_CACHE = 6;
356 private bool _finished; 398 private bool _finished;
357 public bool Finished 399 public bool Finished
358 { 400 {
359 get { return _finished; } 401 get { return _finished; }
360 } 402 }
361 // public int HttpBodyMaxLen = 2048; // not implemented 403 // public int HttpBodyMaxLen = 2048; // not implemented
@@ -367,9 +409,14 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
367 public bool HttpVerifyCert = true; 409 public bool HttpVerifyCert = true;
368 public IWorkItemResult WorkItem = null; 410 public IWorkItemResult WorkItem = null;
369 411
412 //public bool HttpVerboseThrottle = true; // not implemented
413 public List<string> HttpCustomHeaders = null;
414 public bool HttpPragmaNoCache = true;
415 private Thread httpThread;
416
370 // Request info 417 // Request info
371 private UUID _itemID; 418 private UUID _itemID;
372 public UUID ItemID 419 public UUID ItemID
373 { 420 {
374 get { return _itemID; } 421 get { return _itemID; }
375 set { _itemID = value; } 422 set { _itemID = value; }
@@ -385,7 +432,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
385 public string proxyexcepts; 432 public string proxyexcepts;
386 public string OutboundBody; 433 public string OutboundBody;
387 private UUID _reqID; 434 private UUID _reqID;
388 public UUID ReqID 435 public UUID ReqID
389 { 436 {
390 get { return _reqID; } 437 get { return _reqID; }
391 set { _reqID = value; } 438 set { _reqID = value; }
@@ -434,20 +481,34 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
434 Request.Method = HttpMethod; 481 Request.Method = HttpMethod;
435 Request.ContentType = HttpMIMEType; 482 Request.ContentType = HttpMIMEType;
436 483
437 if(!HttpVerifyCert) 484 if (!HttpVerifyCert)
438 { 485 {
439 // We could hijack Connection Group Name to identify 486 // We could hijack Connection Group Name to identify
440 // a desired security exception. But at the moment we'll use a dummy header instead. 487 // a desired security exception. But at the moment we'll use a dummy header instead.
441 Request.Headers.Add("NoVerifyCert", "true"); 488 Request.Headers.Add("NoVerifyCert", "true");
442 } 489 }
443 if (proxyurl != null && proxyurl.Length > 0) 490// else
491// {
492// Request.ConnectionGroupName="Verify";
493// }
494 if (!HttpPragmaNoCache)
495 {
496 Request.Headers.Add("Pragma", "no-cache");
497 }
498 if (HttpCustomHeaders != null)
444 { 499 {
445 if (proxyexcepts != null && proxyexcepts.Length > 0) 500 for (int i = 0; i < HttpCustomHeaders.Count; i += 2)
501 Request.Headers.Add(HttpCustomHeaders[i],
502 HttpCustomHeaders[i+1]);
503 }
504 if (proxyurl != null && proxyurl.Length > 0)
505 {
506 if (proxyexcepts != null && proxyexcepts.Length > 0)
446 { 507 {
447 string[] elist = proxyexcepts.Split(';'); 508 string[] elist = proxyexcepts.Split(';');
448 Request.Proxy = new WebProxy(proxyurl, true, elist); 509 Request.Proxy = new WebProxy(proxyurl, true, elist);
449 } 510 }
450 else 511 else
451 { 512 {
452 Request.Proxy = new WebProxy(proxyurl, true); 513 Request.Proxy = new WebProxy(proxyurl, true);
453 } 514 }
@@ -460,7 +521,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
460 Request.Headers[entry.Key] = entry.Value; 521 Request.Headers[entry.Key] = entry.Value;
461 522
462 // Encode outbound data 523 // Encode outbound data
463 if (OutboundBody.Length > 0) 524 if (OutboundBody.Length > 0)
464 { 525 {
465 byte[] data = Util.UTF8.GetBytes(OutboundBody); 526 byte[] data = Util.UTF8.GetBytes(OutboundBody);
466 527
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index da59eab..f2922d6 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
50 public string url; 50 public string url;
51 public UUID urlcode; 51 public UUID urlcode;
52 public Dictionary<UUID, RequestData> requests; 52 public Dictionary<UUID, RequestData> requests;
53 public bool isSsl;
53 } 54 }
54 55
55 public class RequestData 56 public class RequestData
@@ -83,20 +84,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
83 private Dictionary<string, UrlData> m_UrlMap = 84 private Dictionary<string, UrlData> m_UrlMap =
84 new Dictionary<string, UrlData>(); 85 new Dictionary<string, UrlData>();
85 86
86 /// <summary> 87 private uint m_HttpsPort = 0;
87 /// Maximum number of external urls that can be set up by this module.
88 /// </summary>
89 private int m_TotalUrls = 15000;
90
91 private uint https_port = 0;
92 private IHttpServer m_HttpServer = null; 88 private IHttpServer m_HttpServer = null;
93 private IHttpServer m_HttpsServer = null; 89 private IHttpServer m_HttpsServer = null;
94 90
95 private string m_ExternalHostNameForLSL = ""; 91 public string ExternalHostNameForLSL { get; private set; }
96 public string ExternalHostNameForLSL 92
97 { 93 /// <summary>
98 get { return m_ExternalHostNameForLSL; } 94 /// The default maximum number of urls
99 } 95 /// </summary>
96 public const int DefaultTotalUrls = 15000;
97
98 /// <summary>
99 /// Maximum number of external urls that can be set up by this module.
100 /// </summary>
101 public int TotalUrls { get; set; }
100 102
101 public Type ReplaceableInterface 103 public Type ReplaceableInterface
102 { 104 {
@@ -110,17 +112,27 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
110 112
111 public void Initialise(IConfigSource config) 113 public void Initialise(IConfigSource config)
112 { 114 {
113 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); 115 IConfig networkConfig = config.Configs["Network"];
114 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false); 116
115 if (ssl_enabled) 117 if (networkConfig != null)
116 { 118 {
117 https_port = (uint) config.Configs["Network"].GetInt("https_port",0); 119 ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", null);
120
121 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener", false);
122
123 if (ssl_enabled)
124 m_HttpsPort = (uint)config.Configs["Network"].GetInt("https_port", (int)m_HttpsPort);
118 } 125 }
119 126
127 if (ExternalHostNameForLSL == null)
128 ExternalHostNameForLSL = System.Environment.MachineName;
129
120 IConfig llFunctionsConfig = config.Configs["LL-Functions"]; 130 IConfig llFunctionsConfig = config.Configs["LL-Functions"];
121 131
122 if (llFunctionsConfig != null) 132 if (llFunctionsConfig != null)
123 m_TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", m_TotalUrls); 133 TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", DefaultTotalUrls);
134 else
135 TotalUrls = DefaultTotalUrls;
124 } 136 }
125 137
126 public void PostInitialise() 138 public void PostInitialise()
@@ -136,9 +148,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
136 m_HttpServer = MainServer.Instance; 148 m_HttpServer = MainServer.Instance;
137 // 149 //
138 // We can use the https if it is enabled 150 // We can use the https if it is enabled
139 if (https_port > 0) 151 if (m_HttpsPort > 0)
140 { 152 {
141 m_HttpsServer = MainServer.GetHttpServer(https_port); 153 m_HttpsServer = MainServer.GetHttpServer(m_HttpsPort);
142 } 154 }
143 } 155 }
144 156
@@ -171,12 +183,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
171 183
172 lock (m_UrlMap) 184 lock (m_UrlMap)
173 { 185 {
174 if (m_UrlMap.Count >= m_TotalUrls) 186 if (m_UrlMap.Count >= TotalUrls)
175 { 187 {
176 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 188 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
177 return urlcode; 189 return urlcode;
178 } 190 }
179 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString(); 191 string url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString();
180 192
181 UrlData urlData = new UrlData(); 193 UrlData urlData = new UrlData();
182 urlData.hostID = host.UUID; 194 urlData.hostID = host.UUID;
@@ -184,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
184 urlData.engine = engine; 196 urlData.engine = engine;
185 urlData.url = url; 197 urlData.url = url;
186 urlData.urlcode = urlcode; 198 urlData.urlcode = urlcode;
199 urlData.isSsl = false;
187 urlData.requests = new Dictionary<UUID, RequestData>(); 200 urlData.requests = new Dictionary<UUID, RequestData>();
188 201
189 m_UrlMap[url] = urlData; 202 m_UrlMap[url] = urlData;
@@ -216,12 +229,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
216 229
217 lock (m_UrlMap) 230 lock (m_UrlMap)
218 { 231 {
219 if (m_UrlMap.Count >= m_TotalUrls) 232 if (m_UrlMap.Count >= TotalUrls)
220 { 233 {
221 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 234 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
222 return urlcode; 235 return urlcode;
223 } 236 }
224 string url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString(); 237 string url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString();
225 238
226 UrlData urlData = new UrlData(); 239 UrlData urlData = new UrlData();
227 urlData.hostID = host.UUID; 240 urlData.hostID = host.UUID;
@@ -229,6 +242,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
229 urlData.engine = engine; 242 urlData.engine = engine;
230 urlData.url = url; 243 urlData.url = url;
231 urlData.urlcode = urlcode; 244 urlData.urlcode = urlcode;
245 urlData.isSsl = true;
232 urlData.requests = new Dictionary<UUID, RequestData>(); 246 urlData.requests = new Dictionary<UUID, RequestData>();
233 247
234 248
@@ -301,6 +315,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
301 UrlData urlData = m_RequestMap[request]; 315 UrlData urlData = m_RequestMap[request];
302 if (!urlData.requests[request].responseSent) 316 if (!urlData.requests[request].responseSent)
303 { 317 {
318 string responseBody = body;
319 if (urlData.requests[request].responseType.Equals("text/plain"))
320 {
321 string value;
322 if (urlData.requests[request].headers.TryGetValue("user-agent", out value))
323 {
324 if (value != null && value.IndexOf("MSIE") >= 0)
325 {
326 // wrap the html escaped response if the target client is IE
327 // It ignores "text/plain" if the body is html
328 responseBody = "<html>" + System.Web.HttpUtility.HtmlEncode(body) + "</html>";
329 }
330 }
331 }
332
304 urlData.requests[request].responseCode = status; 333 urlData.requests[request].responseCode = status;
305 urlData.requests[request].responseBody = body; 334 urlData.requests[request].responseBody = body;
306 //urlData.requests[request].ev.Set(); 335 //urlData.requests[request].ev.Set();
@@ -336,7 +365,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
336 365
337 public int GetFreeUrls() 366 public int GetFreeUrls()
338 { 367 {
339 return m_TotalUrls - m_UrlMap.Count; 368 lock (m_UrlMap)
369 return TotalUrls - m_UrlMap.Count;
340 } 370 }
341 371
342 public void ScriptRemoved(UUID itemID) 372 public void ScriptRemoved(UUID itemID)
@@ -394,7 +424,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
394 424
395 private void RemoveUrl(UrlData data) 425 private void RemoveUrl(UrlData data)
396 { 426 {
397 m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); 427 if (data.isSsl)
428 m_HttpsServer.RemoveHTTPHandler("", "/lslhttps/"+data.urlcode.ToString()+"/");
429 else
430 m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/");
398 } 431 }
399 432
400 private Hashtable NoEvents(UUID requestID, UUID sessionID) 433 private Hashtable NoEvents(UUID requestID, UUID sessionID)
@@ -527,7 +560,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
527 { 560 {
528 Hashtable headers = (Hashtable)request["headers"]; 561 Hashtable headers = (Hashtable)request["headers"];
529 562
530// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; 563// string uri_full = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/";
531 564
532 int pos1 = uri.IndexOf("/");// /lslhttp 565 int pos1 = uri.IndexOf("/");// /lslhttp
533 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 566 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
@@ -543,10 +576,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
543 UrlData url = null; 576 UrlData url = null;
544 string urlkey; 577 string urlkey;
545 if (!is_ssl) 578 if (!is_ssl)
546 urlkey = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; 579 urlkey = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp;
547 //m_UrlMap[]; 580 //m_UrlMap[];
548 else 581 else
549 urlkey = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; 582 urlkey = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp;
550 583
551 if (m_UrlMap.ContainsKey(urlkey)) 584 if (m_UrlMap.ContainsKey(urlkey))
552 { 585 {
diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
index f6e1d39..fccf053 100644
--- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
@@ -41,7 +41,7 @@ using System.Linq.Expressions;
41namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms 41namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
42{ 42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] 43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")]
44 class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms 44 public class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms
45 { 45 {
46 private static readonly ILog m_log = 46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -262,6 +262,8 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
262 return "modInvokeR"; 262 return "modInvokeR";
263 else if (sid.ReturnType == typeof(object[])) 263 else if (sid.ReturnType == typeof(object[]))
264 return "modInvokeL"; 264 return "modInvokeL";
265 else if (sid.ReturnType == typeof(void))
266 return "modInvokeN";
265 267
266 m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); 268 m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name);
267 } 269 }
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index f395441..2fc89fc 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
516 foreach (string line in GetLines(data, dataDelim)) 516 foreach (string line in GetLines(data, dataDelim))
517 { 517 {
518 string nextLine = line.Trim(); 518 string nextLine = line.Trim();
519
520// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
521
519 //replace with switch, or even better, do some proper parsing 522 //replace with switch, or even better, do some proper parsing
520 if (nextLine.StartsWith("MoveTo")) 523 if (nextLine.StartsWith("MoveTo"))
521 { 524 {
@@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
829 float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); 832 float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
830 PointF point = new PointF(x, y); 833 PointF point = new PointF(x, y);
831 points[i / 2] = point; 834 points[i / 2] = point;
835
836// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
832 } 837 }
833 } 838 }
834 } 839 }
@@ -838,13 +843,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
838 try 843 try
839 { 844 {
840 WebRequest request = HttpWebRequest.Create(url); 845 WebRequest request = HttpWebRequest.Create(url);
841//Ckrinke: Comment out for now as 'str' is unused. Bring it back into play later when it is used. 846
842//Ckrinke Stream str = null; 847 using (HttpWebResponse response = (HttpWebResponse)(request).GetResponse())
843 HttpWebResponse response = (HttpWebResponse)(request).GetResponse();
844 if (response.StatusCode == HttpStatusCode.OK)
845 { 848 {
846 Bitmap image = new Bitmap(response.GetResponseStream()); 849 if (response.StatusCode == HttpStatusCode.OK)
847 return image; 850 {
851 using (Stream s = response.GetResponseStream())
852 {
853 Bitmap image = new Bitmap(s);
854 return image;
855 }
856 }
848 } 857 }
849 } 858 }
850 catch { } 859 catch { }
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
index 385f5ad..cbffca7 100644
--- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
@@ -111,13 +111,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
111 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); 111 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
112 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); 112 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
113 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); 113 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
114 114 if (config.Configs["XMLRPC"] != null)
115 try
116 {
117 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
118 }
119 catch (Exception)
120 { 115 {
116 try
117 {
118 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
119 }
120 catch (Exception)
121 {
122 }
121 } 123 }
122 } 124 }
123 125
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index 5836eb9..b61062f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -75,7 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
75 public void Close() { } 75 public void Close() { }
76 public void PostInitialise() { } 76 public void PostInitialise() { }
77 77
78
79 ///<summary> 78 ///<summary>
80 /// 79 ///
81 ///</summary> 80 ///</summary>
@@ -136,7 +135,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
136 ///</summary> 135 ///</summary>
137 public void AddRegion(Scene scene) 136 public void AddRegion(Scene scene)
138 { 137 {
139 if (! m_enabled) 138 if (!m_enabled)
140 return; 139 return;
141 140
142 // Every shared region module has to maintain an indepedent list of 141 // Every shared region module has to maintain an indepedent list of
@@ -209,6 +208,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
209 208
210 using (Image mapTile = tileGenerator.CreateMapTile()) 209 using (Image mapTile = tileGenerator.CreateMapTile())
211 { 210 {
211 // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there
212 // is no static map tile.
213 if (mapTile == null)
214 return;
215
212 using (MemoryStream stream = new MemoryStream()) 216 using (MemoryStream stream = new MemoryStream())
213 { 217 {
214 mapTile.Save(stream, ImageFormat.Jpeg); 218 mapTile.Save(stream, ImageFormat.Jpeg);
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/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index b485194..8b8bb37 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
219 { 219 {
220// m_log.DebugFormat( 220// m_log.DebugFormat(
221// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", 221// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
222// s.RegionInfo.RegionName, destination.RegionHandle); 222// destination.RegionName, destination.RegionID);
223 223
224 return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); 224 return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData);
225 } 225 }
226 226
227// m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle); 227// m_log.DebugFormat(
228// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate",
229// destination.RegionName, destination.RegionID);
230
228 return false; 231 return false;
229 } 232 }
230 233
@@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
239 // note that we really don't need the GridRegion for this call 242 // note that we really don't need the GridRegion for this call
240 foreach (Scene s in m_scenes.Values) 243 foreach (Scene s in m_scenes.Values)
241 { 244 {
242 //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); 245// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
243 s.IncomingChildAgentDataUpdate(cAgentData); 246 s.IncomingChildAgentDataUpdate(cAgentData);
244 } 247 }
245 248
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..a990898 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -44,6 +44,7 @@ using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream; 44using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode; 45using CompressionMode = Ionic.Zlib.CompressionMode;
46using OpenSim.Framework.Serialization.External; 46using OpenSim.Framework.Serialization.External;
47using PermissionMask = OpenSim.Framework.PermissionMask;
47 48
48namespace OpenSim.Region.CoreModules.World.Archiver 49namespace OpenSim.Region.CoreModules.World.Archiver
49{ 50{
@@ -167,7 +168,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
167 } 168 }
168 scenesGroup.CalcSceneLocations(); 169 scenesGroup.CalcSceneLocations();
169 170
170
171 m_archiveWriter = new TarArchiveWriter(m_saveStream); 171 m_archiveWriter = new TarArchiveWriter(m_saveStream);
172 172
173 try 173 try
@@ -216,7 +216,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
216 } 216 }
217 } 217 }
218 218
219
220 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) 219 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
221 { 220 {
222 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); 221 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
@@ -540,7 +539,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
540 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 539 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
541 } 540 }
542 541
543
544 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) 542 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
545 { 543 {
546 if (regionDir != string.Empty) 544 if (regionDir != string.Empty)
@@ -560,8 +558,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
560 foreach (ILandObject lo in landObjects) 558 foreach (ILandObject lo in landObjects)
561 { 559 {
562 LandData landData = lo.LandData; 560 LandData landData = lo.LandData;
563 string landDataPath = String.Format("{0}{1}{2}.xml", 561 string landDataPath
564 regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); 562 = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData));
565 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); 563 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
566 } 564 }
567 565
@@ -590,21 +588,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
590 } 588 }
591 } 589 }
592 590
593 protected void ReceivedAllAssets( 591 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
594 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
595 { 592 {
596 foreach (UUID uuid in assetsNotFoundUuids) 593 string errorMessage;
594
595 if (timedOut)
597 { 596 {
598 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); 597 errorMessage = "Loading assets timed out";
599 } 598 }
599 else
600 {
601 foreach (UUID uuid in assetsNotFoundUuids)
602 {
603 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
604 }
600 605
601 // m_log.InfoFormat( 606 // m_log.InfoFormat(
602 // "[ARCHIVER]: Received {0} of {1} assets requested", 607 // "[ARCHIVER]: Received {0} of {1} assets requested",
603 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); 608 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
604 609
605 CloseArchive(String.Empty); 610 errorMessage = String.Empty;
611 }
612
613 CloseArchive(errorMessage);
606 } 614 }
607
608 615
609 /// <summary> 616 /// <summary>
610 /// Closes the archive and notifies that we're done. 617 /// Closes the archive and notifies that we're done.
@@ -629,6 +636,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
629 636
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); 637 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 } 638 }
632
633 } 639 }
634} 640}
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..ada7ecc 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
@@ -156,6 +156,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
156 156
157 foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) 157 foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids)
158 { 158 {
159// m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key);
160
159// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); 161// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback);
160 AssetBase asset = m_assetService.Get(kvp.Key.ToString()); 162 AssetBase asset = m_assetService.Get(kvp.Key.ToString());
161 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); 163 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset);
@@ -164,7 +166,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
164 166
165 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) 167 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args)
166 { 168 {
167 bool close = true; 169 bool timedOut = true;
168 170
169 try 171 try
170 { 172 {
@@ -174,7 +176,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
174 // the final request came in (assuming that such a thing is possible) 176 // the final request came in (assuming that such a thing is possible)
175 if (m_requestState == RequestState.Completed) 177 if (m_requestState == RequestState.Completed)
176 { 178 {
177 close = false; 179 timedOut = false;
178 return; 180 return;
179 } 181 }
180 182
@@ -223,8 +225,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
223 } 225 }
224 finally 226 finally
225 { 227 {
226 if (close) 228 if (timedOut)
227 m_assetsArchiver.ForceClose(); 229 Util.FireAndForget(PerformAssetsRequestCallback, true);
228 } 230 }
229 } 231 }
230 232
@@ -290,7 +292,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
290 292
291 // We want to stop using the asset cache thread asap 293 // 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 294 // as we now need to do the work of producing the rest of the archive
293 Util.FireAndForget(PerformAssetsRequestCallback); 295 Util.FireAndForget(PerformAssetsRequestCallback, false);
294 } 296 }
295 else 297 else
296 { 298 {
@@ -311,9 +313,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
311 { 313 {
312 Culture.SetCurrentCulture(); 314 Culture.SetCurrentCulture();
313 315
316 Boolean timedOut = (Boolean)o;
317
314 try 318 try
315 { 319 {
316 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); 320 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut);
317 } 321 }
318 catch (Exception e) 322 catch (Exception e)
319 { 323 {
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/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
index 3b84d57..4d49794 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
@@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
117 117
118 m_module.Scene.RegionInfo.RegionSettings.Save(); 118 m_module.Scene.RegionInfo.RegionSettings.Save();
119 m_module.TriggerRegionInfoChange(); 119 m_module.TriggerRegionInfoChange();
120 m_module.sendRegionInfoPacketToAll(); 120 m_module.sendRegionHandshakeToAll();
121 } 121 }
122 } 122 }
123 } 123 }
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/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
index 7fc358d..73c592d 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
@@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
95 return null; 95 return null;
96 } 96 }
97 97
98 public ILandObject GetLandObject(Vector3 position)
99 {
100 return GetLandObject(position.X, position.Y);
101 }
102
98 public ILandObject GetLandObject(int x, int y) 103 public ILandObject GetLandObject(int x, int y)
99 { 104 {
100 if (m_landManagementModule != null) 105 if (m_landManagementModule != null)
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/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index 8a422b0..40638f8 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -77,42 +77,48 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 { 77 {
78 bool drawPrimVolume = true; 78 bool drawPrimVolume = true;
79 bool textureTerrain = false; 79 bool textureTerrain = false;
80 bool generateMaptiles = true;
81 Bitmap mapbmp;
80 82
81 try 83 string[] configSections = new string[] { "Map", "Startup" };
82 {
83 IConfig startupConfig = m_config.Configs["Startup"];
84 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
85 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
86 }
87 catch
88 {
89 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
90 }
91 84
92 if (textureTerrain) 85 drawPrimVolume
93 { 86 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume);
94 terrainRenderer = new TexturedMapTileRenderer(); 87 textureTerrain
95 } 88 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain);
96 else 89 generateMaptiles
90 = Util.GetConfigVarFromSections<bool>(m_config, "GenerateMaptiles", configSections, generateMaptiles);
91
92 if (generateMaptiles)
97 { 93 {
98 terrainRenderer = new ShadedMapTileRenderer(); 94 if (textureTerrain)
99 } 95 {
100 terrainRenderer.Initialise(m_scene, m_config); 96 terrainRenderer = new TexturedMapTileRenderer();
97 }
98 else
99 {
100 terrainRenderer = new ShadedMapTileRenderer();
101 }
101 102
102 Bitmap mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 103 terrainRenderer.Initialise(m_scene, m_config);
103 //long t = System.Environment.TickCount;
104 //for (int i = 0; i < 10; ++i) {
105 terrainRenderer.TerrainToBitmap(mapbmp);
106 //}
107 //t = System.Environment.TickCount - t;
108 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
109 104
105 mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
106 //long t = System.Environment.TickCount;
107 //for (int i = 0; i < 10; ++i) {
108 terrainRenderer.TerrainToBitmap(mapbmp);
109 //}
110 //t = System.Environment.TickCount - t;
111 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
110 112
111 if (drawPrimVolume) 113 if (drawPrimVolume)
114 {
115 DrawObjectVolume(m_scene, mapbmp);
116 }
117 }
118 else
112 { 119 {
113 DrawObjectVolume(m_scene, mapbmp); 120 mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID);
114 } 121 }
115
116 return mapbmp; 122 return mapbmp;
117 } 123 }
118 124
@@ -139,9 +145,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
139 { 145 {
140 m_config = source; 146 m_config = source;
141 147
142 IConfig startupConfig = m_config.Configs["Startup"]; 148 if (Util.GetConfigVarFromSections<string>(
143 if (startupConfig.GetString("MapImageModule", "MapImageModule") != 149 m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule")
144 "MapImageModule")
145 return; 150 return;
146 151
147 m_Enabled = true; 152 m_Enabled = true;
@@ -222,6 +227,49 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
222// } 227// }
223// } 228// }
224 229
230 private Bitmap FetchTexture(UUID id)
231 {
232 AssetBase asset = m_scene.AssetService.Get(id.ToString());
233
234 if (asset != null)
235 {
236 m_log.DebugFormat("[MAPTILE]: Static map image texture {0} found for {1}", id, m_scene.Name);
237 }
238 else
239 {
240 m_log.WarnFormat("[MAPTILE]: Static map image texture {0} not found for {1}", id, m_scene.Name);
241 return null;
242 }
243
244 ManagedImage managedImage;
245 Image image;
246
247 try
248 {
249 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
250 return new Bitmap(image);
251 else
252 return null;
253 }
254 catch (DllNotFoundException)
255 {
256 m_log.ErrorFormat("[MAPTILE]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
257
258 }
259 catch (IndexOutOfRangeException)
260 {
261 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
262
263 }
264 catch (Exception)
265 {
266 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
267
268 }
269 return null;
270
271 }
272
225 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) 273 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
226 { 274 {
227 int tc = 0; 275 int tc = 0;
diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
index 6f92ef6..f13d648 100644
--- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
+++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
@@ -198,12 +198,12 @@ namespace OpenSim.Region.CoreModules.World.LightShare
198 if (m_scene.RegionInfo.WindlightSettings.valid) 198 if (m_scene.RegionInfo.WindlightSettings.valid)
199 { 199 {
200 List<byte[]> param = compileWindlightSettings(wl); 200 List<byte[]> param = compileWindlightSettings(wl);
201 client.SendGenericMessage("Windlight", param); 201 client.SendGenericMessage("Windlight", UUID.Random(), param);
202 } 202 }
203 else 203 else
204 { 204 {
205 List<byte[]> param = new List<byte[]>(); 205 List<byte[]> param = new List<byte[]>();
206 client.SendGenericMessage("WindlightReset", param); 206 client.SendGenericMessage("WindlightReset", UUID.Random(), param);
207 } 207 }
208 } 208 }
209 } 209 }
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/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
index eb4731c..28daf2f 100644
--- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.CoreModules.World.Objects.BuySell 43namespace OpenSim.Region.CoreModules.World.Objects.BuySell
43{ 44{
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index ab8f143..e434b2e 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 }
@@ -414,7 +416,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
414 416
415 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
416 { 418 {
417 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 419 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
418 return; 420 return;
419 } 421 }
420 422
@@ -423,7 +425,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
423 425
424 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
425 { 427 {
426 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 428 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
427 return; 429 return;
428 } 430 }
429 431
@@ -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,61 @@ 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("LightCutoff", s.LightCutoff);
596 cdl.AddRow("LightEntry", s.LightEntry);
597 cdl.AddRow("LightFalloff", s.LightFalloff);
598 cdl.AddRow("LightIntensity", s.LightIntensity);
599 cdl.AddRow("LightRadius", s.LightRadius);
600 cdl.AddRow("Location (relative)", sop.RelativePosition);
601 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
602 cdl.AddRow("PathBegin", s.PathBegin);
603 cdl.AddRow("PathEnd", s.PathEnd);
604 cdl.AddRow("PathCurve", s.PathCurve);
605 cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
606 cdl.AddRow("PathRevolutions", s.PathRevolutions);
607 cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
608 cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
609 cdl.AddRow("FlexiDrag", s.PathSkew);
610 cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
611 cdl.AddRow("PathTwist", s.PathTwist);
612 cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
613 cdl.AddRow("PCode", s.PCode);
614 cdl.AddRow("ProfileBegin", s.ProfileBegin);
615 cdl.AddRow("ProfileEnd", s.ProfileEnd);
616 cdl.AddRow("ProfileHollow", s.ProfileHollow);
617 cdl.AddRow("ProfileShape", s.ProfileShape);
618 cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
619 cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
620 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
621 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
622 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
623 cdl.AddRow("Rotation (Relative)", sop.RotationOffset);
624 cdl.AddRow("Rotation (World)", sop.GetWorldRotation());
625 cdl.AddRow("Scale", s.Scale);
626 cdl.AddRow(
627 "SculptData",
628 string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
629 cdl.AddRow("SculptEntry", s.SculptEntry);
630 cdl.AddRow("SculptTexture", s.SculptTexture);
631 cdl.AddRow("SculptType", s.SculptType);
632 cdl.AddRow("State", s.State);
633
634 // TODO, unpack and display texture entries
635 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
636 }
637
580 object itemsOutput; 638 object itemsOutput;
581 if (showFull) 639 if (showFull)
582 { 640 {
@@ -588,7 +646,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
588 itemsOutput = sop.Inventory.Count; 646 itemsOutput = sop.Inventory.Count;
589 } 647 }
590 648
591
592 cdl.AddRow("Items", itemsOutput); 649 cdl.AddRow("Items", itemsOutput);
593 650
594 return sb.Append(cdl.ToString()); 651 return sb.Append(cdl.ToString());
@@ -842,17 +899,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
842 899
843 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 900 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
844 { 901 {
845 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 902 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
846 endVector = Vector3.Zero; 903 endVector = Vector3.Zero;
847 904
848 return false; 905 return false;
849 } 906 }
850 907
851 string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); 908 string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single();
852 909
853 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 910 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
854 { 911 {
855 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 912 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
856 return false; 913 return false;
857 } 914 }
858 915
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index ddaa227..79dd4a0 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces; 38using OpenSim.Services.Interfaces;
39 39
40using Mono.Addins; 40using Mono.Addins;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.CoreModules.World.Permissions 43namespace OpenSim.Region.CoreModules.World.Permissions
43{ 44{
@@ -156,9 +157,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
156 157
157 public void Initialise(IConfigSource config) 158 public void Initialise(IConfigSource config)
158 { 159 {
159 IConfig myConfig = config.Configs["Startup"]; 160 string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules",
160 161 new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
161 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule");
162 162
163 List<string> modules = new List<string>(permissionModules.Split(',')); 163 List<string> modules = new List<string>(permissionModules.Split(','));
164 164
@@ -167,26 +167,34 @@ namespace OpenSim.Region.CoreModules.World.Permissions
167 167
168 m_Enabled = true; 168 m_Enabled = true;
169 169
170 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); 170 m_allowGridGods = Util.GetConfigVarFromSections<bool>(config, "allow_grid_gods",
171 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); 171 new string[] { "Startup", "Permissions" }, false);
172 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); 172 m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(config, "serverside_object_permissions",
173 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); 173 new string[] { "Startup", "Permissions" }, true);
174 m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); 174 m_propagatePermissions = Util.GetConfigVarFromSections<bool>(config, "propagate_permissions",
175 m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true); 175 new string[] { "Startup", "Permissions" }, true);
176 176 m_RegionOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_owner_is_god",
177 m_SimpleBuildPermissions = myConfig.GetBoolean("simple_build_permissions", false); 177 new string[] { "Startup", "Permissions" }, true);
178 m_RegionManagerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_manager_is_god",
179 new string[] { "Startup", "Permissions" }, false);
180 m_ParcelOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "parcel_owner_is_god",
181 new string[] { "Startup", "Permissions" }, true);
182
183 m_SimpleBuildPermissions = Util.GetConfigVarFromSections<bool>(config, "simple_build_permissions",
184 new string[] { "Startup", "Permissions" }, false);
178 185
179 m_allowedScriptCreators 186 m_allowedScriptCreators
180 = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators); 187 = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators);
181 m_allowedScriptEditors 188 m_allowedScriptEditors
182 = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); 189 = ParseUserSetConfigSetting(config, "allowed_script_editors", m_allowedScriptEditors);
183 190
184 if (m_bypassPermissions) 191 if (m_bypassPermissions)
185 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); 192 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks");
186 else 193 else
187 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); 194 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks");
188 195
189 string grant = myConfig.GetString("GrantLSL", ""); 196 string grant = Util.GetConfigVarFromSections<string>(config, "GrantLSL",
197 new string[] { "Startup", "Permissions" }, string.Empty);
190 if (grant.Length > 0) 198 if (grant.Length > 0)
191 { 199 {
192 foreach (string uuidl in grant.Split(',')) 200 foreach (string uuidl in grant.Split(','))
@@ -196,7 +204,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
196 } 204 }
197 } 205 }
198 206
199 grant = myConfig.GetString("GrantCS", ""); 207 grant = Util.GetConfigVarFromSections<string>(config, "GrantCS",
208 new string[] { "Startup", "Permissions" }, string.Empty);
200 if (grant.Length > 0) 209 if (grant.Length > 0)
201 { 210 {
202 foreach (string uuidl in grant.Split(',')) 211 foreach (string uuidl in grant.Split(','))
@@ -206,7 +215,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
206 } 215 }
207 } 216 }
208 217
209 grant = myConfig.GetString("GrantVB", ""); 218 grant = Util.GetConfigVarFromSections<string>(config, "GrantVB",
219 new string[] { "Startup", "Permissions" }, string.Empty);
210 if (grant.Length > 0) 220 if (grant.Length > 0)
211 { 221 {
212 foreach (string uuidl in grant.Split(',')) 222 foreach (string uuidl in grant.Split(','))
@@ -216,7 +226,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
216 } 226 }
217 } 227 }
218 228
219 grant = myConfig.GetString("GrantJS", ""); 229 grant = Util.GetConfigVarFromSections<string>(config, "GrantJS",
230 new string[] { "Startup", "Permissions" }, string.Empty);
220 if (grant.Length > 0) 231 if (grant.Length > 0)
221 { 232 {
222 foreach (string uuidl in grant.Split(',')) 233 foreach (string uuidl in grant.Split(','))
@@ -226,7 +237,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
226 } 237 }
227 } 238 }
228 239
229 grant = myConfig.GetString("GrantYP", ""); 240 grant = Util.GetConfigVarFromSections<string>(config, "GrantYP",
241 new string[] { "Startup", "Permissions" }, string.Empty);
230 if (grant.Length > 0) 242 if (grant.Length > 0)
231 { 243 {
232 foreach (string uuidl in grant.Split(',')) 244 foreach (string uuidl in grant.Split(','))
@@ -464,11 +476,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions
464 /// <param name="settingName"></param> 476 /// <param name="settingName"></param>
465 /// <param name="defaultValue">The default value for this attribute</param> 477 /// <param name="defaultValue">The default value for this attribute</param>
466 /// <returns>The parsed value</returns> 478 /// <returns>The parsed value</returns>
467 private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue) 479 private static UserSet ParseUserSetConfigSetting(IConfigSource config, string settingName, UserSet defaultValue)
468 { 480 {
469 UserSet userSet = defaultValue; 481 UserSet userSet = defaultValue;
470 482
471 string rawSetting = config.GetString(settingName, defaultValue.ToString()); 483 string rawSetting = Util.GetConfigVarFromSections<string>(config, settingName,
484 new string[] {"Startup", "Permissions"}, defaultValue.ToString());
472 485
473 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term 486 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term
474 // this should disappear. 487 // this should disappear.
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
index 7825e3e..b4348c9 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
@@ -35,11 +35,12 @@ using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Scenes.Serialization; 36using OpenSim.Region.Framework.Scenes.Serialization;
37using OpenSim.Tests.Common; 37using OpenSim.Tests.Common;
38using OpenMetaverse.StructuredData;
38 39
39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 40namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
40{ 41{
41 [TestFixture] 42 [TestFixture]
42 public class SerialiserTests 43 public class SerialiserTests : OpenSimTestCase
43 { 44 {
44 private string xml = @" 45 private string xml = @"
45 <SceneObjectGroup> 46 <SceneObjectGroup>
@@ -143,6 +144,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
143 <Flags>None</Flags> 144 <Flags>None</Flags>
144 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> 145 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
145 <CollisionSoundVolume>0</CollisionSoundVolume> 146 <CollisionSoundVolume>0</CollisionSoundVolume>
147 <DynAttrs><llsd><map><key>MyStore</key><map><key>the answer</key><integer>42</integer></map></map></llsd></DynAttrs>
146 </SceneObjectPart> 148 </SceneObjectPart>
147 </RootPart> 149 </RootPart>
148 <OtherParts /> 150 <OtherParts />
@@ -331,6 +333,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
331 <EveryoneMask>0</EveryoneMask> 333 <EveryoneMask>0</EveryoneMask>
332 <NextOwnerMask>2147483647</NextOwnerMask> 334 <NextOwnerMask>2147483647</NextOwnerMask>
333 <Flags>None</Flags> 335 <Flags>None</Flags>
336 <DynAttrs><llsd><map><key>MyStore</key><map><key>last words</key><string>Rosebud</string></map></map></llsd></DynAttrs>
334 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> 337 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar>
335 </SceneObjectPart> 338 </SceneObjectPart>
336 <OtherParts /> 339 <OtherParts />
@@ -359,6 +362,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
359 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 362 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
360 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); 363 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
361 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); 364 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide"));
365 OSDMap store = rootPart.DynAttrs["MyStore"];
366 Assert.AreEqual(42, store["the answer"].AsInteger());
362 367
363 // TODO: Check other properties 368 // TODO: Check other properties
364 } 369 }
@@ -409,6 +414,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
409 rp.CreatorID = rpCreatorId; 414 rp.CreatorID = rpCreatorId;
410 rp.Shape = shape; 415 rp.Shape = shape;
411 416
417 string daStoreName = "MyStore";
418 string daKey = "foo";
419 string daValue = "bar";
420 OSDMap myStore = new OSDMap();
421 myStore.Add(daKey, daValue);
422 rp.DynAttrs = new DAMap();
423 rp.DynAttrs[daStoreName] = myStore;
424
412 SceneObjectGroup so = new SceneObjectGroup(rp); 425 SceneObjectGroup so = new SceneObjectGroup(rp);
413 426
414 // Need to add the object to the scene so that the request to get script state succeeds 427 // Need to add the object to the scene so that the request to get script state succeeds
@@ -424,6 +437,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
424 UUID uuid = UUID.Zero; 437 UUID uuid = UUID.Zero;
425 string name = null; 438 string name = null;
426 UUID creatorId = UUID.Zero; 439 UUID creatorId = UUID.Zero;
440 DAMap daMap = null;
427 441
428 while (xtr.Read() && xtr.Name != "SceneObjectPart") 442 while (xtr.Read() && xtr.Name != "SceneObjectPart")
429 { 443 {
@@ -449,6 +463,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
449 creatorId = UUID.Parse(xtr.ReadElementString("UUID")); 463 creatorId = UUID.Parse(xtr.ReadElementString("UUID"));
450 xtr.ReadEndElement(); 464 xtr.ReadEndElement();
451 break; 465 break;
466 case "DynAttrs":
467 daMap = new DAMap();
468 daMap.ReadXml(xtr);
469 break;
452 } 470 }
453 } 471 }
454 472
@@ -462,6 +480,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
462 Assert.That(uuid, Is.EqualTo(rpUuid)); 480 Assert.That(uuid, Is.EqualTo(rpUuid));
463 Assert.That(name, Is.EqualTo(rpName)); 481 Assert.That(name, Is.EqualTo(rpName));
464 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 482 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
483 Assert.NotNull(daMap);
484 Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString());
465 } 485 }
466 486
467 [Test] 487 [Test]
@@ -476,6 +496,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
476 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); 496 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946")));
477 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); 497 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef")));
478 Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); 498 Assert.That(rootPart.Name, Is.EqualTo("PrimFun"));
499 OSDMap store = rootPart.DynAttrs["MyStore"];
500 Assert.AreEqual("Rosebud", store["last words"].AsString());
479 501
480 // TODO: Check other properties 502 // TODO: Check other properties
481 } 503 }
@@ -500,6 +522,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
500 rp.CreatorID = rpCreatorId; 522 rp.CreatorID = rpCreatorId;
501 rp.Shape = shape; 523 rp.Shape = shape;
502 524
525 string daStoreName = "MyStore";
526 string daKey = "foo";
527 string daValue = "bar";
528 OSDMap myStore = new OSDMap();
529 myStore.Add(daKey, daValue);
530 rp.DynAttrs = new DAMap();
531 rp.DynAttrs[daStoreName] = myStore;
532
503 SceneObjectGroup so = new SceneObjectGroup(rp); 533 SceneObjectGroup so = new SceneObjectGroup(rp);
504 534
505 // Need to add the object to the scene so that the request to get script state succeeds 535 // Need to add the object to the scene so that the request to get script state succeeds
@@ -516,6 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
516 UUID uuid = UUID.Zero; 546 UUID uuid = UUID.Zero;
517 string name = null; 547 string name = null;
518 UUID creatorId = UUID.Zero; 548 UUID creatorId = UUID.Zero;
549 DAMap daMap = null;
519 550
520 while (xtr.Read() && xtr.Name != "SceneObjectPart") 551 while (xtr.Read() && xtr.Name != "SceneObjectPart")
521 { 552 {
@@ -537,6 +568,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
537 creatorId = UUID.Parse(xtr.ReadElementString("Guid")); 568 creatorId = UUID.Parse(xtr.ReadElementString("Guid"));
538 xtr.ReadEndElement(); 569 xtr.ReadEndElement();
539 break; 570 break;
571 case "DynAttrs":
572 daMap = new DAMap();
573 daMap.ReadXml(xtr);
574 break;
540 } 575 }
541 } 576 }
542 577
@@ -549,6 +584,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
549 Assert.That(uuid, Is.EqualTo(rpUuid)); 584 Assert.That(uuid, Is.EqualTo(rpUuid));
550 Assert.That(name, Is.EqualTo(rpName)); 585 Assert.That(name, Is.EqualTo(rpName));
551 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 586 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
587 Assert.NotNull(daMap);
588 Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString());
552 } 589 }
553 } 590 }
554} \ No newline at end of file 591} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 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/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
index 7ef44db..d38f34b 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
@@ -74,8 +74,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
74 { 74 {
75 m_config = source; 75 m_config = source;
76 76
77 IConfig startupConfig = m_config.Configs["Startup"]; 77 if (Util.GetConfigVarFromSections<string>(
78 if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") 78 m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "Warp3DImageModule")
79 return; 79 return;
80 80
81 m_Enabled = true; 81 m_Enabled = true;
@@ -157,16 +157,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
157 bool drawPrimVolume = true; 157 bool drawPrimVolume = true;
158 bool textureTerrain = true; 158 bool textureTerrain = true;
159 159
160 try 160 string[] configSections = new string[] { "Map", "Startup" };
161 { 161
162 IConfig startupConfig = m_config.Configs["Startup"]; 162 drawPrimVolume
163 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); 163 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume);
164 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); 164 textureTerrain
165 } 165 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain);
166 catch
167 {
168 m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig");
169 }
170 166
171 m_colors.Clear(); 167 m_colors.Clear();
172 168
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/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index 2184a59..bf18616 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -89,11 +89,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
89 #region INonSharedRegionModule Members 89 #region INonSharedRegionModule Members
90 public virtual void Initialise (IConfigSource config) 90 public virtual void Initialise (IConfigSource config)
91 { 91 {
92 IConfig startupConfig = config.Configs["Startup"]; 92 string[] configSections = new string[] { "Map", "Startup" };
93 if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap")
94 m_Enabled = true;
95 93
96 blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; 94 if (Util.GetConfigVarFromSections<string>(
95 config, "WorldMapModule", configSections, "WorldMap") == "WorldMap")
96 m_Enabled = true;
97
98 blacklistTimeout
99 = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
97 } 100 }
98 101
99 public virtual void AddRegion (Scene scene) 102 public virtual void AddRegion (Scene scene)
diff --git a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
index 5e62f23..dd48dd5 100644
--- a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
+++ b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
@@ -113,9 +113,17 @@ namespace OpenSim.Region.DataSnapshot
113 try 113 try
114 { 114 {
115 m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled); 115 m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled);
116 IConfig conf = config.Configs["GridService"]; 116 string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
117 if (conf != null) 117 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
118 m_gridinfo.Add("gatekeeperURL", conf.GetString("Gatekeeper", String.Empty)); 118 // Legacy. Remove soon!
119 if (string.IsNullOrEmpty(gatekeeper))
120 {
121 IConfig conf = config.Configs["GridService"];
122 if (conf != null)
123 gatekeeper = conf.GetString("Gatekeeper", gatekeeper);
124 }
125 if (!string.IsNullOrEmpty(gatekeeper))
126 m_gridinfo.Add("gatekeeperURL", gatekeeper);
119 127
120 m_gridinfo.Add( 128 m_gridinfo.Add(
121 "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo")); 129 "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo"));
@@ -140,8 +148,6 @@ namespace OpenSim.Region.DataSnapshot
140 return; 148 return;
141 } 149 }
142 150
143 if (m_enabled)
144 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
145 } 151 }
146 152
147 } 153 }
@@ -155,8 +161,22 @@ namespace OpenSim.Region.DataSnapshot
155 161
156 m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName); 162 m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
157 163
158 m_snapStore.AddScene(scene); 164 if (!m_servicesNotified)
165 {
166 m_hostname = scene.RegionInfo.ExternalHostName;
167 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
168
169 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
170 new DataRequestHandler(scene, this);
171
172 if (m_dataServices != "" && m_dataServices != "noservices")
173 NotifyDataServices(m_dataServices, "online");
174
175 m_servicesNotified = true;
176 }
177
159 m_scenes.Add(scene); 178 m_scenes.Add(scene);
179 m_snapStore.AddScene(scene);
160 180
161 Assembly currentasm = Assembly.GetExecutingAssembly(); 181 Assembly currentasm = Assembly.GetExecutingAssembly();
162 182
@@ -181,22 +201,6 @@ namespace OpenSim.Region.DataSnapshot
181 } 201 }
182 } 202 }
183 203
184 // Must be done here because on shared modules, PostInitialise() will run
185 // BEFORE any scenes are registered. There is no "all scenes have been loaded"
186 // kind of callback because scenes may be created dynamically, so we cannot
187 // have that info, ever.
188 if (!m_servicesNotified)
189 {
190 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
191 new DataRequestHandler(m_scenes[0], this);
192
193 m_hostname = m_scenes[0].RegionInfo.ExternalHostName;
194
195 if (m_dataServices != "" && m_dataServices != "noservices")
196 NotifyDataServices(m_dataServices, "online");
197
198 m_servicesNotified = true;
199 }
200 } 204 }
201 205
202 public void RemoveRegion(Scene scene) 206 public void RemoveRegion(Scene scene)
diff --git a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs
index b926264..0e7df07 100644
--- a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index d781eae..3c1247f 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -54,6 +54,10 @@ namespace OpenSim.Region.Framework.Interfaces
54 /// RezAttachments. This should only be called upon login on the first region. 54 /// RezAttachments. This should only be called upon login on the first region.
55 /// Attachment rezzings on crossings and TPs are done in a different way. 55 /// Attachment rezzings on crossings and TPs are done in a different way.
56 /// </summary> 56 /// </summary>
57 /// <remarks>
58 /// This is only actually necessary for viewers which do not have a current outfit folder (these viewers make
59 /// their own attachment calls on login) and agents which have attachments but no viewer (e.g. NPCs).
60 /// </remarks>
57 /// <param name="sp"></param> 61 /// <param name="sp"></param>
58 void RezAttachments(IScenePresence sp); 62 void RezAttachments(IScenePresence sp);
59 63
@@ -77,14 +81,16 @@ namespace OpenSim.Region.Framework.Interfaces
77 void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); 81 void DeleteAttachmentsFromScene(IScenePresence sp, bool silent);
78 82
79 /// <summary> 83 /// <summary>
80 /// Attach an object to an avatar 84 /// Attach an object to an avatar.
81 /// </summary> 85 /// </summary>
82 /// <param name="sp"></param> 86 /// <param name="sp"></param>
83 /// <param name="grp"></param> 87 /// <param name="grp"></param>
84 /// <param name="AttachmentPt"></param> 88 /// <param name="AttachmentPt"></param>
85 /// <param name="silent"></param> 89 /// <param name="silent"></param>
90 /// <param name="addToInventory">If true then add object to user inventory</param>
91 /// <param name="append">Append to attachment point rather than replace.</param>
86 /// <returns>true if the object was successfully attached, false otherwise</returns> 92 /// <returns>true if the object was successfully attached, false otherwise</returns>
87 bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp); 93 bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool addToInventory, bool append);
88 94
89 /// <summary> 95 /// <summary>
90 /// Rez an attachment from user inventory and change inventory status to match. 96 /// Rez an attachment from user inventory and change inventory status to match.
diff --git a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
index 522c82d..30d404e 100644
--- a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs
@@ -40,19 +40,19 @@ namespace OpenSim.Region.Framework.Interfaces
40 /// </summary> 40 /// </summary>
41 /// <param name="agentId"></param> 41 /// <param name="agentId"></param>
42 /// <param name="capsObjectPath"></param> 42 /// <param name="capsObjectPath"></param>
43 void CreateCaps(UUID agentId); 43 void CreateCaps(UUID agentId, uint circuitCode);
44 44
45 /// <summary> 45 /// <summary>
46 /// Remove the caps handler for a given agent. 46 /// Remove the caps handler for a given agent.
47 /// </summary> 47 /// </summary>
48 /// <param name="agentId"></param> 48 /// <param name="agentId"></param>
49 void RemoveCaps(UUID agentId); 49 void RemoveCaps(UUID agentId, uint circuitCode);
50 50
51 /// <summary> 51 /// <summary>
52 /// Will return null if the agent doesn't have a caps handler registered 52 /// Will return null if the agent doesn't have a caps handler registered
53 /// </summary> 53 /// </summary>
54 /// <param name="agentId"></param> 54 /// <param name="agentId"></param>
55 Caps GetCapsForUser(UUID agentId); 55 Caps GetCapsForUser(uint circuitCode);
56 56
57 void SetAgentCapsSeeds(AgentCircuitData agent); 57 void SetAgentCapsSeeds(AgentCircuitData agent);
58 58
@@ -65,5 +65,7 @@ namespace OpenSim.Region.Framework.Interfaces
65 void DropChildSeed(UUID agentID, ulong handle); 65 void DropChildSeed(UUID agentID, ulong handle);
66 66
67 string GetCapsPath(UUID agentId); 67 string GetCapsPath(UUID agentId);
68
69 void ActivateCaps(uint circuitCode);
68 } 70 }
69} 71}
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs
new file mode 100644
index 0000000..5e633e6
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs
@@ -0,0 +1,51 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.Framework.Interfaces
34{
35 public delegate bool HandlerDelegate(IClientAPI client, FloaterData data, string[] msg);
36
37 public abstract class FloaterData
38 {
39 public abstract int Channel { get; }
40 public abstract string FloaterName { get; }
41 public virtual string XmlName { get; set; }
42 public virtual HandlerDelegate Handler { get; set; }
43 }
44
45
46 public interface IDynamicFloaterModule
47 {
48 void DoUserFloater(UUID agentID, FloaterData dialogData, string configuration);
49 void FloaterControl(ScenePresence sp, FloaterData d, string msg);
50 }
51}
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs
new file mode 100644
index 0000000..08b71e4
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using OpenMetaverse;
30using OpenSim.Framework;
31
32namespace OpenSim.Region.Framework.Interfaces
33{
34 public enum InsertLocation : int
35 {
36 Agent = 1,
37 World = 2,
38 Tools = 3,
39 Advanced = 4,
40 Admin = 5
41 }
42
43 public enum UserMode : int
44 {
45 Normal = 0,
46 God = 3
47 }
48
49 public delegate void CustomMenuHandler(string action, UUID agentID, List<uint> selection);
50
51 public interface IDynamicMenuModule
52 {
53 void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler);
54 void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler);
55 void RemoveMenuItem(string action);
56 }
57}
diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
index de0f2a3..eb6c5ac 100644
--- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
+++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
@@ -36,6 +36,9 @@ namespace OpenSim.Region.Framework.Interfaces
36 HTTP_MIMETYPE = 1, 36 HTTP_MIMETYPE = 1,
37 HTTP_BODY_MAXLENGTH = 2, 37 HTTP_BODY_MAXLENGTH = 2,
38 HTTP_VERIFY_CERT = 3, 38 HTTP_VERIFY_CERT = 3,
39 HTTP_VERBOSE_THROTTLE = 4,
40 HTTP_CUSTOM_HEADER = 5,
41 HTTP_PRAGMA_NO_CACHE = 6
39 } 42 }
40 43
41 public interface IHttpRequestModule 44 public interface IHttpRequestModule
diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
index da39e95..b67312e 100644
--- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
@@ -31,18 +31,46 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.Framework.Interfaces 32namespace OpenSim.Region.Framework.Interfaces
33{ 33{
34 // these could be expanded at some point to provide more type information
35 // for now value accounts for all base types
36 public enum JsonStoreNodeType
37 {
38 Undefined = 0,
39 Object = 1,
40 Array = 2,
41 Value = 3
42 }
43
44 public enum JsonStoreValueType
45 {
46 Undefined = 0,
47 Boolean = 1,
48 Integer = 2,
49 Float = 3,
50 String = 4,
51 UUID = 5
52 }
53
34 public delegate void TakeValueCallback(string s); 54 public delegate void TakeValueCallback(string s);
35 55
36 public interface IJsonStoreModule 56 public interface IJsonStoreModule
37 { 57 {
58 bool AttachObjectStore(UUID objectID);
38 bool CreateStore(string value, ref UUID result); 59 bool CreateStore(string value, ref UUID result);
39 bool DestroyStore(UUID storeID); 60 bool DestroyStore(UUID storeID);
40 bool TestPath(UUID storeID, string path, bool useJson); 61
62 JsonStoreNodeType GetNodeType(UUID storeID, string path);
63 JsonStoreValueType GetValueType(UUID storeID, string path);
64
65 bool TestStore(UUID storeID);
66
41 bool SetValue(UUID storeID, string path, string value, bool useJson); 67 bool SetValue(UUID storeID, string path, string value, bool useJson);
42 bool RemoveValue(UUID storeID, string path); 68 bool RemoveValue(UUID storeID, string path);
43 bool GetValue(UUID storeID, string path, bool useJson, out string value); 69 bool GetValue(UUID storeID, string path, bool useJson, out string value);
44 70
45 void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); 71 void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
46 void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); 72 void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
73
74 int GetArrayLength(UUID storeID, string path);
47 } 75 }
48} 76}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs
index 8b43d42..c5e678b 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs
@@ -9,7 +9,7 @@
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
@@ -25,19 +25,19 @@
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
28namespace OpenSim.ApplicationPlugins.Rest.Inventory 28using System;
29{ 29using System.Collections.Generic;
30 /// <summary> 30using OpenMetaverse;
31 /// This interface represents the boundary between the general purpose 31using OpenSim.Framework;
32 /// REST plugin handling, and the functionally specific handlers. The 32using OpenSim.Region.Framework.Scenes;
33 /// handler knows only to initialize and terminate all such handlers
34 /// that it finds. Implementing this interface identifies the class as
35 /// a REST handler implementation.
36 /// </summary>
37 33
38 internal interface IRest 34namespace OpenSim.Region.Framework.Interfaces
35{
36 public interface ISceneCommandsModule
39 { 37 {
40 void Initialize(); 38 /// <summary>
41 void Close(); 39 /// Sets the scene debug options.
40 /// </summary>
41 void SetSceneDebugOptions(Dictionary<string, string> options);
42 } 42 }
43} 43} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
index 143af48..ced4e91 100644
--- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
@@ -52,7 +52,18 @@ namespace OpenSim.Region.Framework.Interfaces
52 string GetXMLState(UUID itemID); 52 string GetXMLState(UUID itemID);
53 bool SetXMLState(UUID itemID, string xml); 53 bool SetXMLState(UUID itemID, string xml);
54 54
55 /// <summary>
56 /// Post a script event to a single script.
57 /// </summary>
58 /// <returns>true if the post suceeded, false if it did not</returns>
59 /// <param name='itemID'>The item ID of the script.</param>
60 /// <param name='name'>The name of the event.</param>
61 /// <param name='args'>
62 /// The arguments of the event. These are in the order in which they appear.
63 /// e.g. for http_request this will be an object array of key request_id, string method, string body
64 /// </param>
55 bool PostScriptEvent(UUID itemID, string name, Object[] args); 65 bool PostScriptEvent(UUID itemID, string name, Object[] args);
66
56 bool PostObjectEvent(UUID itemID, string name, Object[] args); 67 bool PostObjectEvent(UUID itemID, string name, Object[] args);
57 68
58 /// <summary> 69 /// <summary>
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
index 8cef14e..6effcc1 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
@@ -26,18 +26,22 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenMetaverse;
29using OpenMetaverse.StructuredData; 30using OpenMetaverse.StructuredData;
30 31
31namespace OpenSim.Region.Framework.Interfaces 32namespace OpenSim.Region.Framework.Interfaces
32{ 33{
34 public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features);
35
33 /// <summary> 36 /// <summary>
34 /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. 37 /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability.
35 /// </summary> 38 /// </summary>
36 public interface ISimulatorFeaturesModule 39 public interface ISimulatorFeaturesModule
37 { 40 {
41 event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
38 void AddFeature(string name, OSD value); 42 void AddFeature(string name, OSD value);
39 bool RemoveFeature(string name); 43 bool RemoveFeature(string name);
40 bool TryGetFeature(string name, out OSD value); 44 bool TryGetFeature(string name, out OSD value);
41 OSDMap GetFeatures(); 45 OSDMap GetFeatures();
42 } 46 }
43} \ No newline at end of file 47}
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/Properties/AssemblyInfo.cs b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs
index 9b504c0..167c248 100644
--- a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index 65ae445..66edfed 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -87,13 +87,24 @@ namespace OpenSim.Region.Framework.Scenes.Animation
87 return false; 87 return false;
88 } 88 }
89 89
90 public bool Remove(UUID animID) 90 /// <summary>
91 /// Remove the specified animation
92 /// </summary>
93 /// <param name='animID'></param>
94 /// <param name='allowNoDefault'>
95 /// If true, then the default animation can be entirely removed.
96 /// If false, then removing the default animation will reset it to the simulator default (currently STAND).
97 /// </param>
98 public bool Remove(UUID animID, bool allowNoDefault)
91 { 99 {
92 lock (m_animations) 100 lock (m_animations)
93 { 101 {
94 if (m_defaultAnimation.AnimID == animID) 102 if (m_defaultAnimation.AnimID == animID)
95 { 103 {
96 m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero); 104 if (allowNoDefault)
105 m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero);
106 else
107 ResetDefaultAnimation();
97 } 108 }
98 else if (HasAnimation(animID)) 109 else if (HasAnimation(animID))
99 { 110 {
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 9458079..65c279e 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;
@@ -86,6 +87,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
86 return; 87 return;
87 88
88 // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name); 89 // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name);
90 if (m_scenePresence.Scene.DebugAnimations)
91 m_log.DebugFormat(
92 "[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}",
93 GetAnimName(animID), animID, m_scenePresence.Name);
89 94
90 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) 95 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
91 SendAnimPack(); 96 SendAnimPack();
@@ -108,12 +113,25 @@ namespace OpenSim.Region.Framework.Scenes.Animation
108 AddAnimation(animID, objectID); 113 AddAnimation(animID, objectID);
109 } 114 }
110 115
111 public void RemoveAnimation(UUID animID) 116 /// <summary>
117 /// Remove the specified animation
118 /// </summary>
119 /// <param name='animID'></param>
120 /// <param name='allowNoDefault'>
121 /// If true, then the default animation can be entirely removed.
122 /// If false, then removing the default animation will reset it to the simulator default (currently STAND).
123 /// </param>
124 public void RemoveAnimation(UUID animID, bool allowNoDefault)
112 { 125 {
113 if (m_scenePresence.IsChildAgent) 126 if (m_scenePresence.IsChildAgent)
114 return; 127 return;
115 128
116 if (m_animations.Remove(animID)) 129 if (m_scenePresence.Scene.DebugAnimations)
130 m_log.DebugFormat(
131 "[SCENE PRESENCE ANIMATOR]: Removing animation {0} {1} for {2}",
132 GetAnimName(animID), animID, m_scenePresence.Name);
133
134 if (m_animations.Remove(animID, allowNoDefault))
117 SendAnimPack(); 135 SendAnimPack();
118 } 136 }
119 137
@@ -127,7 +145,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
127 if (addRemove) 145 if (addRemove)
128 m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero); 146 m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero);
129 else 147 else
130 m_animations.Remove(animID); 148 m_animations.Remove(animID, true);
131 } 149 }
132 if(sendPack) 150 if(sendPack)
133 SendAnimPack(); 151 SendAnimPack();
@@ -145,14 +163,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation
145 if (animID == UUID.Zero) 163 if (animID == UUID.Zero)
146 return; 164 return;
147 165
148 RemoveAnimation(animID); 166 RemoveAnimation(animID, true);
149 } 167 }
150 168
151 public void ResetAnimations() 169 public void ResetAnimations()
152 { 170 {
153// m_log.DebugFormat( 171 if (m_scenePresence.Scene.DebugAnimations)
154// "[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}", 172 m_log.DebugFormat(
155// m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName); 173 "[SCENE PRESENCE ANIMATOR]: Resetting animations for {0} in {1}",
174 m_scenePresence.Name, m_scenePresence.Scene.RegionInfo.RegionName);
156 175
157 m_animations.Clear(); 176 m_animations.Clear();
158 } 177 }
@@ -519,6 +538,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
519 if (m_scenePresence.IsChildAgent) 538 if (m_scenePresence.IsChildAgent)
520 return; 539 return;
521 540
541// m_log.DebugFormat(
542// "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'",
543// string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())),
544// string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())),
545// string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString())));
546
522 m_scenePresence.Scene.ForEachClient( 547 m_scenePresence.Scene.ForEachClient(
523 delegate(IClientAPI client) 548 delegate(IClientAPI client)
524 { 549 {
@@ -557,5 +582,21 @@ namespace OpenSim.Region.Framework.Scenes.Animation
557 582
558 SendAnimPack(animIDs, sequenceNums, objectIDs); 583 SendAnimPack(animIDs, sequenceNums, objectIDs);
559 } 584 }
585
586 public string GetAnimName(UUID animId)
587 {
588 string animName;
589
590 if (!DefaultAvatarAnimations.AnimsNames.TryGetValue(animId, out animName))
591 {
592 AssetMetadata amd = m_scenePresence.Scene.AssetService.GetMetadata(animId.ToString());
593 if (amd != null)
594 animName = amd.Name;
595 else
596 animName = "Unknown";
597 }
598
599 return animName;
600 }
560 } 601 }
561} 602}
diff --git a/OpenSim/Region/Framework/Scenes/Border.cs b/OpenSim/Region/Framework/Scenes/Border.cs
index c6a6511..08c0c31 100644
--- a/OpenSim/Region/Framework/Scenes/Border.cs
+++ b/OpenSim/Region/Framework/Scenes/Border.cs
@@ -33,8 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Framework.Scenes 33namespace OpenSim.Region.Framework.Scenes
34{ 34{
35 public class Border 35 public class Border
36 { 36 {
37
38 /// <summary> 37 /// <summary>
39 /// Line perpendicular to the Direction Cardinal. Z value is the 38 /// Line perpendicular to the Direction Cardinal. Z value is the
40 /// </summary> 39 /// </summary>
@@ -81,6 +80,10 @@ namespace OpenSim.Region.Framework.Scenes
81 TriggerRegionY = triggerRegionY; 80 TriggerRegionY = triggerRegionY;
82 } 81 }
83 82
83 /// <summary>
84 /// Tests to see if the given position would cross this border.
85 /// </summary>
86 /// <returns></returns>
84 public bool TestCross(Vector3 position) 87 public bool TestCross(Vector3 position)
85 { 88 {
86 bool result = false; 89 bool result = false;
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..4733547 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -550,6 +550,20 @@ namespace OpenSim.Region.Framework.Scenes
550 /// </remarks> 550 /// </remarks>
551 public event ScriptControlEvent OnScriptControlEvent; 551 public event ScriptControlEvent OnScriptControlEvent;
552 552
553 public delegate void ScriptMovingStartEvent(uint localID);
554
555 /// <summary>
556 /// TODO: Should be triggered when a physics object starts moving.
557 /// </summary>
558 public event ScriptMovingStartEvent OnScriptMovingStartEvent;
559
560 public delegate void ScriptMovingEndEvent(uint localID);
561
562 /// <summary>
563 /// TODO: Should be triggered when a physics object stops moving.
564 /// </summary>
565 public event ScriptMovingEndEvent OnScriptMovingEndEvent;
566
553 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); 567 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
554 568
555 /// <summary> 569 /// <summary>
@@ -755,7 +769,7 @@ namespace OpenSim.Region.Framework.Scenes
755 public event ScriptTimerEvent OnScriptTimerEvent; 769 public event ScriptTimerEvent OnScriptTimerEvent;
756 */ 770 */
757 771
758 public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); 772 public delegate void EstateToolsSunUpdate(ulong regionHandle);
759 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); 773 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
760 774
761 public event EstateToolsSunUpdate OnEstateToolsSunUpdate; 775 public event EstateToolsSunUpdate OnEstateToolsSunUpdate;
@@ -778,6 +792,19 @@ namespace OpenSim.Region.Framework.Scenes
778 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); 792 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
779 793
780 /// <summary> 794 /// <summary>
795 /// Triggered when an object is placed into the physical scene (PhysicsActor created).
796 /// </summary>
797 public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene;
798 /// <summary>
799 /// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
800 /// </summary>
801 /// <remarks>
802 /// Note: this is triggered just before the PhysicsActor is removed from the
803 /// physics engine so the receiver can do any necessary cleanup before its destruction.
804 /// </remarks>
805 public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene;
806
807 /// <summary>
781 /// Triggered when an object is removed from the scene. 808 /// Triggered when an object is removed from the scene.
782 /// </summary> 809 /// </summary>
783 /// <remarks> 810 /// <remarks>
@@ -1527,6 +1554,48 @@ namespace OpenSim.Region.Framework.Scenes
1527 } 1554 }
1528 } 1555 }
1529 1556
1557 public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
1558 {
1559 Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene;
1560 if (handler != null)
1561 {
1562 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1563 {
1564 try
1565 {
1566 d(obj);
1567 }
1568 catch (Exception e)
1569 {
1570 m_log.ErrorFormat(
1571 "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
1572 e.Message, e.StackTrace);
1573 }
1574 }
1575 }
1576 }
1577
1578 public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
1579 {
1580 Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene;
1581 if (handler != null)
1582 {
1583 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1584 {
1585 try
1586 {
1587 d(obj);
1588 }
1589 catch (Exception e)
1590 {
1591 m_log.ErrorFormat(
1592 "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
1593 e.Message, e.StackTrace);
1594 }
1595 }
1596 }
1597 }
1598
1530 public void TriggerShutdown() 1599 public void TriggerShutdown()
1531 { 1600 {
1532 Action handlerShutdown = OnShutdown; 1601 Action handlerShutdown = OnShutdown;
@@ -2238,6 +2307,48 @@ namespace OpenSim.Region.Framework.Scenes
2238 } 2307 }
2239 } 2308 }
2240 2309
2310 public void TriggerMovingStartEvent(uint localID)
2311 {
2312 ScriptMovingStartEvent handlerScriptMovingStartEvent = OnScriptMovingStartEvent;
2313 if (handlerScriptMovingStartEvent != null)
2314 {
2315 foreach (ScriptMovingStartEvent d in handlerScriptMovingStartEvent.GetInvocationList())
2316 {
2317 try
2318 {
2319 d(localID);
2320 }
2321 catch (Exception e)
2322 {
2323 m_log.ErrorFormat(
2324 "[EVENT MANAGER]: Delegate for TriggerMovingStartEvent failed - continuing. {0} {1}",
2325 e.Message, e.StackTrace);
2326 }
2327 }
2328 }
2329 }
2330
2331 public void TriggerMovingEndEvent(uint localID)
2332 {
2333 ScriptMovingEndEvent handlerScriptMovingEndEvent = OnScriptMovingEndEvent;
2334 if (handlerScriptMovingEndEvent != null)
2335 {
2336 foreach (ScriptMovingEndEvent d in handlerScriptMovingEndEvent.GetInvocationList())
2337 {
2338 try
2339 {
2340 d(localID);
2341 }
2342 catch (Exception e)
2343 {
2344 m_log.ErrorFormat(
2345 "[EVENT MANAGER]: Delegate for TriggerMovingEndEvent failed - continuing. {0} {1}",
2346 e.Message, e.StackTrace);
2347 }
2348 }
2349 }
2350 }
2351
2241 public void TriggerRequestChangeWaterHeight(float height) 2352 public void TriggerRequestChangeWaterHeight(float height)
2242 { 2353 {
2243 if (height < 0) 2354 if (height < 0)
@@ -2536,13 +2647,10 @@ namespace OpenSim.Region.Framework.Scenes
2536 } 2647 }
2537 2648
2538 /// <summary> 2649 /// <summary>
2539 /// Updates the system as to how the position of the sun should be handled. 2650 /// Called when the sun's position parameters have changed in the Region and/or Estate
2540 /// </summary> 2651 /// </summary>
2541 /// <param name="regionHandle"></param> 2652 /// <param name="regionHandle">The region that changed</param>
2542 /// <param name="FixedTime">True if the Sun Position is fixed</param> 2653 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 { 2654 {
2547 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate; 2655 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate;
2548 if (handlerEstateToolsSunUpdate != null) 2656 if (handlerEstateToolsSunUpdate != null)
@@ -2551,7 +2659,7 @@ namespace OpenSim.Region.Framework.Scenes
2551 { 2659 {
2552 try 2660 try
2553 { 2661 {
2554 d(regionHandle, FixedTime, useEstateTime, FixedSunHour); 2662 d(regionHandle);
2555 } 2663 }
2556 catch (Exception e) 2664 catch (Exception e)
2557 { 2665 {
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
index 5cfba39..b102e48 100644
--- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
+++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
@@ -22,6 +22,115 @@ using log4net;
22 22
23namespace OpenSim.Region.Framework.Scenes 23namespace OpenSim.Region.Framework.Scenes
24{ 24{
25 public class KeyframeTimer
26 {
27 private static Dictionary<Scene, KeyframeTimer>m_timers =
28 new Dictionary<Scene, KeyframeTimer>();
29
30 private Timer m_timer;
31 private Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>();
32 private object m_lockObject = new object();
33 private object m_timerLock = new object();
34 private const double m_tickDuration = 50.0;
35 private Scene m_scene;
36
37 public double TickDuration
38 {
39 get { return m_tickDuration; }
40 }
41
42 public KeyframeTimer(Scene scene)
43 {
44 m_timer = new Timer();
45 m_timer.Interval = TickDuration;
46 m_timer.AutoReset = true;
47 m_timer.Elapsed += OnTimer;
48
49 m_scene = scene;
50
51 m_timer.Start();
52 }
53
54 private void OnTimer(object sender, ElapsedEventArgs ea)
55 {
56 if (!Monitor.TryEnter(m_timerLock))
57 return;
58
59 try
60 {
61 List<KeyframeMotion> motions;
62
63 lock (m_lockObject)
64 {
65 motions = new List<KeyframeMotion>(m_motions.Keys);
66 }
67
68 foreach (KeyframeMotion m in motions)
69 {
70 try
71 {
72 m.OnTimer(TickDuration);
73 }
74 catch (Exception inner)
75 {
76 // Don't stop processing
77 }
78 }
79 }
80 catch (Exception e)
81 {
82 // Keep running no matter what
83 }
84 finally
85 {
86 Monitor.Exit(m_timerLock);
87 }
88 }
89
90 public static void Add(KeyframeMotion motion)
91 {
92 KeyframeTimer timer;
93
94 if (motion.Scene == null)
95 return;
96
97 lock (m_timers)
98 {
99 if (!m_timers.TryGetValue(motion.Scene, out timer))
100 {
101 timer = new KeyframeTimer(motion.Scene);
102 m_timers[motion.Scene] = timer;
103 }
104 }
105
106 lock (timer.m_lockObject)
107 {
108 timer.m_motions[motion] = null;
109 }
110 }
111
112 public static void Remove(KeyframeMotion motion)
113 {
114 KeyframeTimer timer;
115
116 if (motion.Scene == null)
117 return;
118
119 lock (m_timers)
120 {
121 if (!m_timers.TryGetValue(motion.Scene, out timer))
122 {
123 return;
124 }
125 }
126
127 lock (timer.m_lockObject)
128 {
129 timer.m_motions.Remove(motion);
130 }
131 }
132 }
133
25 [Serializable] 134 [Serializable]
26 public class KeyframeMotion 135 public class KeyframeMotion
27 { 136 {
@@ -63,18 +172,6 @@ namespace OpenSim.Region.Framework.Scenes
63 172
64 private Keyframe[] m_keyframes; 173 private Keyframe[] m_keyframes;
65 174
66 [NonSerialized()]
67 protected Timer m_timer = null;
68
69 // timer lock
70 [NonSerialized()]
71 private object m_onTimerLock;
72
73 // timer overrun detect
74 // prevents overlap or timer events threads frozen on the lock
75 [NonSerialized()]
76 private bool m_inOnTimer;
77
78 // skip timer events. 175 // skip timer events.
79 //timer.stop doesn't assure there aren't event threads still being fired 176 //timer.stop doesn't assure there aren't event threads still being fired
80 [NonSerialized()] 177 [NonSerialized()]
@@ -97,12 +194,21 @@ namespace OpenSim.Region.Framework.Scenes
97 private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; 194 private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation;
98 195
99 private bool m_running = false; 196 private bool m_running = false;
197
100 [NonSerialized()] 198 [NonSerialized()]
101 private bool m_selected = false; 199 private bool m_selected = false;
102 200
103 private int m_iterations = 0; 201 private int m_iterations = 0;
104 202
105 private const double timerInterval = 50.0; 203 private int m_skipLoops = 0;
204
205 [NonSerialized()]
206 private Scene m_scene;
207
208 public Scene Scene
209 {
210 get { return m_scene; }
211 }
106 212
107 public DataFormat Data 213 public DataFormat Data
108 { 214 {
@@ -139,31 +245,16 @@ namespace OpenSim.Region.Framework.Scenes
139 245
140 private void StartTimer() 246 private void StartTimer()
141 { 247 {
142 if (m_timer == null) 248 KeyframeTimer.Add(this);
143 return;
144 m_timerStopped = false; 249 m_timerStopped = false;
145 m_timer.Start();
146 } 250 }
147 251
148 private void StopTimer() 252 private void StopTimer()
149 { 253 {
150 if (m_timer == null || m_timerStopped)
151 return;
152 m_timerStopped = true;
153 m_timer.Stop();
154 }
155
156 private void RemoveTimer()
157 {
158 if (m_timer == null)
159 return;
160 m_timerStopped = true; 254 m_timerStopped = true;
161 m_timer.Stop(); 255 KeyframeTimer.Remove(this);
162 m_timer.Elapsed -= OnTimer;
163 m_timer = null;
164 } 256 }
165 257
166
167 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) 258 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
168 { 259 {
169 KeyframeMotion newMotion = null; 260 KeyframeMotion newMotion = null;
@@ -177,12 +268,15 @@ namespace OpenSim.Region.Framework.Scenes
177 268
178 newMotion.m_group = grp; 269 newMotion.m_group = grp;
179 270
180 if (grp != null && grp.IsSelected) 271 if (grp != null)
181 newMotion.m_selected = true; 272 {
273 newMotion.m_scene = grp.Scene;
274 if (grp.IsSelected)
275 newMotion.m_selected = true;
276 }
182 277
183 newMotion.m_onTimerLock = new object();
184 newMotion.m_timerStopped = false; 278 newMotion.m_timerStopped = false;
185 newMotion.m_inOnTimer = false; 279 newMotion.m_running = true;
186 newMotion.m_isCrossing = false; 280 newMotion.m_isCrossing = false;
187 newMotion.m_waitingCrossing = false; 281 newMotion.m_waitingCrossing = false;
188 } 282 }
@@ -196,37 +290,36 @@ namespace OpenSim.Region.Framework.Scenes
196 290
197 public void UpdateSceneObject(SceneObjectGroup grp) 291 public void UpdateSceneObject(SceneObjectGroup grp)
198 { 292 {
199// lock (m_onTimerLock) 293 m_isCrossing = false;
200 { 294 m_waitingCrossing = false;
201 m_isCrossing = false; 295 StopTimer();
202 m_waitingCrossing = false;
203 StopTimer();
204 296
205 if (grp == null) 297 if (grp == null)
206 return; 298 return;
207 299
208 m_group = grp; 300 m_group = grp;
209 Vector3 grppos = grp.AbsolutePosition; 301 m_scene = grp.Scene;
210 Vector3 offset = grppos - m_serializedPosition;
211 // avoid doing it more than once
212 // current this will happen draging a prim to other region
213 m_serializedPosition = grppos;
214 302
215 m_basePosition += offset; 303 Vector3 grppos = grp.AbsolutePosition;
216 m_currentFrame.Position += offset; 304 Vector3 offset = grppos - m_serializedPosition;
305 // avoid doing it more than once
306 // current this will happen draging a prim to other region
307 m_serializedPosition = grppos;
217 308
218 m_nextPosition += offset; 309 m_basePosition += offset;
310 m_currentFrame.Position += offset;
219 311
220 for (int i = 0; i < m_frames.Count; i++) 312 m_nextPosition += offset;
221 {
222 Keyframe k = m_frames[i];
223 k.Position += offset;
224 m_frames[i]=k;
225 }
226 313
227 if (m_running) 314 for (int i = 0; i < m_frames.Count; i++)
228 Start(); 315 {
316 Keyframe k = m_frames[i];
317 k.Position += offset;
318 m_frames[i]=k;
229 } 319 }
320
321 if (m_running)
322 Start();
230 } 323 }
231 324
232 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) 325 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
@@ -239,11 +332,10 @@ namespace OpenSim.Region.Framework.Scenes
239 { 332 {
240 m_basePosition = grp.AbsolutePosition; 333 m_basePosition = grp.AbsolutePosition;
241 m_baseRotation = grp.GroupRotation; 334 m_baseRotation = grp.GroupRotation;
335 m_scene = grp.Scene;
242 } 336 }
243 337
244 m_onTimerLock = new object();
245 m_timerStopped = true; 338 m_timerStopped = true;
246 m_inOnTimer = false;
247 m_isCrossing = false; 339 m_isCrossing = false;
248 m_waitingCrossing = false; 340 m_waitingCrossing = false;
249 } 341 }
@@ -260,6 +352,7 @@ namespace OpenSim.Region.Framework.Scenes
260 KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); 352 KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data);
261 353
262 newmotion.m_group = newgrp; 354 newmotion.m_group = newgrp;
355 newmotion.m_scene = newgrp.Scene;
263 356
264 if (m_keyframes != null) 357 if (m_keyframes != null)
265 { 358 {
@@ -296,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes
296 public void Delete() 389 public void Delete()
297 { 390 {
298 m_running = false; 391 m_running = false;
299 RemoveTimer(); 392 StopTimer();
300 m_isCrossing = false; 393 m_isCrossing = false;
301 m_waitingCrossing = false; 394 m_waitingCrossing = false;
302 m_frames.Clear(); 395 m_frames.Clear();
@@ -309,27 +402,13 @@ namespace OpenSim.Region.Framework.Scenes
309 m_waitingCrossing = false; 402 m_waitingCrossing = false;
310 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) 403 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0)
311 { 404 {
312 if (m_timer == null)
313 {
314 m_timer = new Timer();
315 m_timer.Interval = timerInterval;
316 m_timer.AutoReset = true;
317 m_timer.Elapsed += OnTimer;
318 }
319 else
320 {
321 StopTimer();
322 m_timer.Interval = timerInterval;
323 }
324
325 m_inOnTimer = false;
326 StartTimer(); 405 StartTimer();
327 m_running = true; 406 m_running = true;
328 } 407 }
329 else 408 else
330 { 409 {
331 m_running = false; 410 m_running = false;
332 RemoveTimer(); 411 StopTimer();
333 } 412 }
334 } 413 }
335 414
@@ -339,7 +418,7 @@ namespace OpenSim.Region.Framework.Scenes
339 m_isCrossing = false; 418 m_isCrossing = false;
340 m_waitingCrossing = false; 419 m_waitingCrossing = false;
341 420
342 RemoveTimer(); 421 StopTimer();
343 422
344 m_basePosition = m_group.AbsolutePosition; 423 m_basePosition = m_group.AbsolutePosition;
345 m_baseRotation = m_group.GroupRotation; 424 m_baseRotation = m_group.GroupRotation;
@@ -354,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes
354 public void Pause() 433 public void Pause()
355 { 434 {
356 m_running = false; 435 m_running = false;
357 RemoveTimer(); 436 StopTimer();
358 437
359 m_group.RootPart.Velocity = Vector3.Zero; 438 m_group.RootPart.Velocity = Vector3.Zero;
360 m_group.RootPart.AngularVelocity = Vector3.Zero; 439 m_group.RootPart.AngularVelocity = Vector3.Zero;
@@ -377,15 +456,11 @@ namespace OpenSim.Region.Framework.Scenes
377 456
378 int start = 0; 457 int start = 0;
379 int end = m_keyframes.Length; 458 int end = m_keyframes.Length;
380// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
381// end = m_keyframes.Length - 1;
382 459
383 if (direction < 0) 460 if (direction < 0)
384 { 461 {
385 start = m_keyframes.Length - 1; 462 start = m_keyframes.Length - 1;
386 end = -1; 463 end = -1;
387// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
388// end = 0;
389 } 464 }
390 465
391 for (int i = start; i != end ; i += direction) 466 for (int i = start; i != end ; i += direction)
@@ -463,189 +538,172 @@ namespace OpenSim.Region.Framework.Scenes
463 } 538 }
464 } 539 }
465 540
466 protected void OnTimer(object sender, ElapsedEventArgs e) 541 public void OnTimer(double tickDuration)
467 { 542 {
468 if (m_timerStopped) // trap events still in air even after a timer.stop 543 if (m_skipLoops > 0)
469 return;
470
471 if (m_inOnTimer) // don't let overruns to happen
472 { 544 {
473 m_log.Warn("[KeyFrame]: timer overrun"); 545 m_skipLoops--;
474 return; 546 return;
475 } 547 }
476 548
549 if (m_timerStopped) // trap events still in air even after a timer.stop
550 return;
551
477 if (m_group == null) 552 if (m_group == null)
478 return; 553 return;
479 554
480 lock (m_onTimerLock) 555 bool update = false;
481 {
482 556
483 m_inOnTimer = true; 557 if (m_selected)
558 {
559 if (m_group.RootPart.Velocity != Vector3.Zero)
560 {
561 m_group.RootPart.Velocity = Vector3.Zero;
562 m_group.SendGroupRootTerseUpdate();
484 563
485 bool update = false; 564 }
565 return;
566 }
486 567
487 try 568 if (m_isCrossing)
569 {
570 // if crossing and timer running then cross failed
571 // wait some time then
572 // retry to set the position that evtually caused the outbound
573 // if still outside region this will call startCrossing below
574 m_isCrossing = false;
575 m_group.AbsolutePosition = m_nextPosition;
576 if (!m_isCrossing)
488 { 577 {
489 if (m_selected) 578 StopTimer();
490 { 579 StartTimer();
491 if (m_group.RootPart.Velocity != Vector3.Zero) 580 }
492 { 581 return;
493 m_group.RootPart.Velocity = Vector3.Zero; 582 }
494 m_group.SendGroupRootTerseUpdate();
495// m_group.RootPart.ScheduleTerseUpdate();
496 583
497 } 584 if (m_frames.Count == 0)
498 m_inOnTimer = false; 585 {
499 return; 586 GetNextList();
500 }
501 587
502 if (m_isCrossing) 588 if (m_frames.Count == 0)
503 { 589 {
504 // if crossing and timer running then cross failed 590 Stop();
505 // wait some time then 591 Scene scene = m_group.Scene;
506 // retry to set the position that evtually caused the outbound
507 // if still outside region this will call startCrossing below
508 m_isCrossing = false;
509 m_group.AbsolutePosition = m_nextPosition;
510 if (!m_isCrossing)
511 {
512 StopTimer();
513 m_timer.Interval = timerInterval;
514 StartTimer();
515 }
516 m_inOnTimer = false;
517 return;
518 }
519 592
520 if (m_frames.Count == 0) 593 IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>();
594 foreach (IScriptModule m in scriptModules)
521 { 595 {
522 GetNextList(); 596 if (m == null)
597 continue;
598 m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
599 }
523 600
524 if (m_frames.Count == 0) 601 return;
525 { 602 }
526 Stop();
527 m_inOnTimer = false;
528 return;
529 }
530 603
531 m_currentFrame = m_frames[0]; 604 m_currentFrame = m_frames[0];
532 m_currentFrame.TimeMS += (int)timerInterval; 605 m_currentFrame.TimeMS += (int)tickDuration;
533 606
534 //force a update on a keyframe transition 607 //force a update on a keyframe transition
535 update = true; 608 update = true;
536 } 609 }
537 610
538 m_currentFrame.TimeMS -= (int)timerInterval; 611 m_currentFrame.TimeMS -= (int)tickDuration;
539 612
540 // Do the frame processing 613 // Do the frame processing
541 double steps = (double)m_currentFrame.TimeMS / timerInterval; 614 double steps = (double)m_currentFrame.TimeMS / tickDuration;
542 615
543 if (steps <= 0.0) 616 if (steps <= 0.0)
544 { 617 {
545 m_group.RootPart.Velocity = Vector3.Zero; 618 m_group.RootPart.Velocity = Vector3.Zero;
546 m_group.RootPart.AngularVelocity = Vector3.Zero; 619 m_group.RootPart.AngularVelocity = Vector3.Zero;
547 620
548 m_nextPosition = (Vector3)m_currentFrame.Position; 621 m_nextPosition = (Vector3)m_currentFrame.Position;
549 m_group.AbsolutePosition = m_nextPosition; 622 m_group.AbsolutePosition = m_nextPosition;
550 623
551 // we are sending imediate updates, no doing force a extra terseUpdate 624 // we are sending imediate updates, no doing force a extra terseUpdate
552// m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); 625 // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
553 626
554 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; 627 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;
555 m_frames.RemoveAt(0); 628 m_frames.RemoveAt(0);
556 if (m_frames.Count > 0) 629 if (m_frames.Count > 0)
557 m_currentFrame = m_frames[0]; 630 m_currentFrame = m_frames[0];
558 631
559 update = true; 632 update = true;
560 } 633 }
561 else 634 else
562 { 635 {
563 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; 636 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
564 637
565 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; 638 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition;
566 Vector3 motionThisFrame = v / (float)steps; 639 Vector3 motionThisFrame = v / (float)steps;
567 v = v * 1000 / m_currentFrame.TimeMS; 640 v = v * 1000 / m_currentFrame.TimeMS;
568 641
569 if (Vector3.Mag(motionThisFrame) >= 0.05f) 642 if (Vector3.Mag(motionThisFrame) >= 0.05f)
570 { 643 {
571 // m_group.AbsolutePosition += motionThisFrame; 644 // m_group.AbsolutePosition += motionThisFrame;
572 m_nextPosition = m_group.AbsolutePosition + motionThisFrame; 645 m_nextPosition = m_group.AbsolutePosition + motionThisFrame;
573 m_group.AbsolutePosition = m_nextPosition; 646 m_group.AbsolutePosition = m_nextPosition;
574 647
575 m_group.RootPart.Velocity = v; 648 m_group.RootPart.Velocity = v;
576 update = true; 649 update = true;
577 } 650 }
578 651
579 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) 652 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
580 { 653 {
581 Quaternion current = m_group.GroupRotation; 654 Quaternion current = m_group.GroupRotation;
582 655
583 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); 656 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete);
584 step.Normalize(); 657 step.Normalize();
585/* use simpler change detection 658/* use simpler change detection
586 * float angle = 0; 659* float angle = 0;
587
588 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
589 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
590 float aa_bb = aa * bb;
591
592 if (aa_bb == 0)
593 {
594 angle = 0;
595 }
596 else
597 {
598 float ab = current.X * step.X +
599 current.Y * step.Y +
600 current.Z * step.Z +
601 current.W * step.W;
602 float q = (ab * ab) / aa_bb;
603
604 if (q > 1.0f)
605 {
606 angle = 0;
607 }
608 else
609 {
610 angle = (float)Math.Acos(2 * q - 1);
611 }
612 }
613
614 if (angle > 0.01f)
615 */
616 if(Math.Abs(step.X - current.X) > 0.001f
617 || Math.Abs(step.Y - current.Y) > 0.001f
618 || Math.Abs(step.Z - current.Z) > 0.001f)
619 // assuming w is a dependente var
620 660
621 { 661 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
622// m_group.UpdateGroupRotationR(step); 662 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
623 m_group.RootPart.RotationOffset = step; 663 float aa_bb = aa * bb;
624 664
625 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); 665 if (aa_bb == 0)
626 update = true; 666 {
627 } 667 angle = 0;
668 }
669 else
670 {
671 float ab = current.X * step.X +
672 current.Y * step.Y +
673 current.Z * step.Z +
674 current.W * step.W;
675 float q = (ab * ab) / aa_bb;
676
677 if (q > 1.0f)
678 {
679 angle = 0;
680 }
681 else
682 {
683 angle = (float)Math.Acos(2 * q - 1);
628 } 684 }
629 } 685 }
630 686
631 if (update) 687 if (angle > 0.01f)
632 m_group.SendGroupRootTerseUpdate(); 688*/
633// m_group.RootPart.ScheduleTerseUpdate(); 689 if(Math.Abs(step.X - current.X) > 0.001f
690 || Math.Abs(step.Y - current.Y) > 0.001f
691 || Math.Abs(step.Z - current.Z) > 0.001f)
692 // assuming w is a dependente var
634 693
694 {
695// m_group.UpdateGroupRotationR(step);
696 m_group.RootPart.RotationOffset = step;
635 697
698 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
699 update = true;
700 }
636 } 701 }
637 catch ( Exception ex) 702 }
638 {
639 // still happening sometimes
640 // lets try to see where
641 m_log.Warn("[KeyFrame]: timer overrun" + ex.Message);
642 }
643 703
644 finally 704 if (update)
645 { 705 {
646 // make sure we do not let this frozen 706 m_group.SendGroupRootTerseUpdate();
647 m_inOnTimer = false;
648 }
649 } 707 }
650 } 708 }
651 709
@@ -677,7 +735,7 @@ namespace OpenSim.Region.Framework.Scenes
677 m_isCrossing = true; 735 m_isCrossing = true;
678 m_waitingCrossing = true; 736 m_waitingCrossing = true;
679 737
680// to remove / retune to smoth crossings 738 // to remove / retune to smoth crossings
681 if (m_group.RootPart.Velocity != Vector3.Zero) 739 if (m_group.RootPart.Velocity != Vector3.Zero)
682 { 740 {
683 m_group.RootPart.Velocity = Vector3.Zero; 741 m_group.RootPart.Velocity = Vector3.Zero;
@@ -696,9 +754,10 @@ namespace OpenSim.Region.Framework.Scenes
696 m_group.SendGroupRootTerseUpdate(); 754 m_group.SendGroupRootTerseUpdate();
697// m_group.RootPart.ScheduleTerseUpdate(); 755// m_group.RootPart.ScheduleTerseUpdate();
698 756
699 if (m_running && m_timer != null) 757 if (m_running)
700 { 758 {
701 m_timer.Interval = 60000; 759 StopTimer();
760 m_skipLoops = 1200; // 60 seconds
702 StartTimer(); 761 StartTimer();
703 } 762 }
704 } 763 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index c9d1205..d2e41f8 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -39,6 +39,7 @@ using OpenSim.Region.Framework;
39using OpenSim.Framework.Client; 39using OpenSim.Framework.Client;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes.Serialization; 41using OpenSim.Region.Framework.Scenes.Serialization;
42using PermissionMask = OpenSim.Framework.PermissionMask;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
@@ -401,29 +402,68 @@ namespace OpenSim.Region.Framework.Scenes
401 if (item.Owner != remoteClient.AgentId) 402 if (item.Owner != remoteClient.AgentId)
402 return; 403 return;
403 404
404 if (UUID.Zero == transactionID) 405 item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255);
405 { 406 item.Name = itemUpd.Name;
406 item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); 407 item.Description = itemUpd.Description;
407 item.Name = itemUpd.Name;
408 item.Description = itemUpd.Description;
409 408
410// m_log.DebugFormat( 409// m_log.DebugFormat(
411// "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}", 410// "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}",
412// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, 411// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
413// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); 412// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
414 413
414 if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
415 {
416 // Create a set of base permissions that will not include export if the user
417 // is not allowed to change the export flag.
418 bool denyExportChange = false;
419
420 m_log.InfoFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
421
422 // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
423 if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
424 denyExportChange = true;
425
426 m_log.InfoFormat("[XXX]: Deny Export Update {0}", denyExportChange);
427
428 // If it is already set, force it set and also force full perm
429 // else prevent setting it. It can and should never be set unless
430 // set in base, so the condition above is valid
431 if (denyExportChange)
432 {
433 // If we are not allowed to change it, then force it to the
434 // original item's setting and if it was on, also force full perm
435 if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
436 {
437 itemUpd.NextPermissions = (uint)(PermissionMask.All);
438 itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export;
439 }
440 else
441 {
442 itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export;
443 }
444 }
445 else
446 {
447 // If the new state is exportable, force full perm
448 if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
449 {
450 m_log.InfoFormat("[XXX]: Force full perm");
451 itemUpd.NextPermissions = (uint)(PermissionMask.All);
452 }
453 }
454
415 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) 455 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
416 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; 456 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
417 item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions; 457 item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
458
418 if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions)) 459 if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions))
419 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; 460 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
420 item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions; 461 item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions;
462
421 if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions)) 463 if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions))
422 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; 464 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
423
424// m_log.DebugFormat("[USER INVENTORY]: item.Flags {0}", item.Flags);
425
426 item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions; 465 item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions;
466
427 item.GroupID = itemUpd.GroupID; 467 item.GroupID = itemUpd.GroupID;
428 item.GroupOwned = itemUpd.GroupOwned; 468 item.GroupOwned = itemUpd.GroupOwned;
429 item.CreationDate = itemUpd.CreationDate; 469 item.CreationDate = itemUpd.CreationDate;
@@ -445,8 +485,10 @@ namespace OpenSim.Region.Framework.Scenes
445 item.SaleType = itemUpd.SaleType; 485 item.SaleType = itemUpd.SaleType;
446 486
447 InventoryService.UpdateItem(item); 487 InventoryService.UpdateItem(item);
488 remoteClient.SendBulkUpdateInventory(item);
448 } 489 }
449 else 490
491 if (UUID.Zero != transactionID)
450 { 492 {
451 if (AgentTransactionsModule != null) 493 if (AgentTransactionsModule != null)
452 { 494 {
@@ -683,12 +725,10 @@ namespace OpenSim.Region.Framework.Scenes
683 itemCopy.SalePrice = item.SalePrice; 725 itemCopy.SalePrice = item.SalePrice;
684 itemCopy.SaleType = item.SaleType; 726 itemCopy.SaleType = item.SaleType;
685 727
686 if (AddInventoryItem(itemCopy)) 728 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
687 { 729 if (invAccess != null)
688 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); 730 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
689 if (invAccess != null) 731 AddInventoryItem(itemCopy);
690 Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); });
691 }
692 732
693 if (!Permissions.BypassPermissions()) 733 if (!Permissions.BypassPermissions())
694 { 734 {
@@ -908,7 +948,7 @@ namespace OpenSim.Region.Framework.Scenes
908 { 948 {
909 CreateNewInventoryItem( 949 CreateNewInventoryItem(
910 remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType, 950 remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType,
911 (uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate, transationID); 951 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0, creationDate, transationID);
912 } 952 }
913 953
914 954
@@ -1037,8 +1077,8 @@ namespace OpenSim.Region.Framework.Scenes
1037 CreateNewInventoryItem( 1077 CreateNewInventoryItem(
1038 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, 1078 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
1039 name, description, 0, callbackID, asset, invType, 1079 name, description, 0, callbackID, asset, invType,
1040 (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, 1080 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All,
1041 (uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch()); 1081 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch());
1042 } 1082 }
1043 else 1083 else
1044 { 1084 {
@@ -1785,6 +1825,21 @@ namespace OpenSim.Region.Framework.Scenes
1785 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> 1825 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1786 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) 1826 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
1787 { 1827 {
1828 return RezNewScript(
1829 agentID,
1830 itemBase,
1831 "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
1832 }
1833
1834 /// <summary>
1835 /// Rez a new script from nothing with given script text.
1836 /// </summary>
1837 /// <param name="remoteClient"></param>
1838 /// <param name="itemBase">Template item.</param>
1839 /// <param name="scriptText"></param>
1840 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1841 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
1842 {
1788 // The part ID is the folder ID! 1843 // The part ID is the folder ID!
1789 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); 1844 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
1790 if (part == null) 1845 if (part == null)
@@ -1804,9 +1859,14 @@ namespace OpenSim.Region.Framework.Scenes
1804 return null; 1859 return null;
1805 } 1860 }
1806 1861
1807 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1862 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}"), 1863 = CreateAsset(
1809 agentID); 1864 itemBase.Name,
1865 itemBase.Description,
1866 (sbyte)itemBase.AssetType,
1867 Encoding.ASCII.GetBytes(scriptText),
1868 agentID);
1869
1810 AssetService.Store(asset); 1870 AssetService.Store(asset);
1811 1871
1812 TaskInventoryItem taskItem = new TaskInventoryItem(); 1872 TaskInventoryItem taskItem = new TaskInventoryItem();
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index e3bc8c7..28fce53 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -51,6 +51,7 @@ using OpenSim.Region.Physics.Manager;
51using Timer=System.Timers.Timer; 51using Timer=System.Timers.Timer;
52using TPFlags = OpenSim.Framework.Constants.TeleportFlags; 52using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
53using GridRegion = OpenSim.Services.Interfaces.GridRegion; 53using GridRegion = OpenSim.Services.Interfaces.GridRegion;
54using PermissionMask = OpenSim.Framework.PermissionMask;
54 55
55namespace OpenSim.Region.Framework.Scenes 56namespace OpenSim.Region.Framework.Scenes
56{ 57{
@@ -68,14 +69,84 @@ namespace OpenSim.Region.Framework.Scenes
68 public bool EmergencyMonitoring = false; 69 public bool EmergencyMonitoring = false;
69 70
70 /// <summary> 71 /// <summary>
72 /// Show debug information about animations.
73 /// </summary>
74 public bool DebugAnimations { get; set; }
75
76 /// <summary>
71 /// Show debug information about teleports. 77 /// Show debug information about teleports.
72 /// </summary> 78 /// </summary>
73 public bool DebugTeleporting { get; private set; } 79 public bool DebugTeleporting { get; set; }
74 80
75 /// <summary> 81 /// <summary>
76 /// Show debug information about the scene loop. 82 /// Show debug information about the scene loop.
77 /// </summary> 83 /// </summary>
78 public bool DebugUpdates { get; private set; } 84 public bool DebugUpdates { get; set; }
85
86 /// <summary>
87 /// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and
88 /// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter).
89 /// </summary>
90 /// <remarks>
91 /// Even if false, the scene will still be saved on clean shutdown.
92 /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels.
93 /// This needs to be fixed.
94 /// </remarks>
95 public bool PeriodicBackup { get; set; }
96
97 /// <summary>
98 /// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even
99 /// if the scene is being shut down for the final time.
100 /// </summary>
101 public bool UseBackup { get; set; }
102
103 /// <summary>
104 /// If false then physical objects are disabled, though collisions will continue as normal.
105 /// </summary>
106 public bool PhysicsEnabled { get; set; }
107
108 /// <summary>
109 /// If false then scripts are not enabled on the smiulator
110 /// </summary>
111 public bool ScriptsEnabled
112 {
113 get { return m_scripts_enabled; }
114 set
115 {
116 if (m_scripts_enabled != value)
117 {
118 if (!value)
119 {
120 m_log.Info("Stopping all Scripts in Scene");
121
122 EntityBase[] entities = Entities.GetEntities();
123 foreach (EntityBase ent in entities)
124 {
125 if (ent is SceneObjectGroup)
126 ((SceneObjectGroup)ent).RemoveScriptInstances(false);
127 }
128 }
129 else
130 {
131 m_log.Info("Starting all Scripts in Scene");
132
133 EntityBase[] entities = Entities.GetEntities();
134 foreach (EntityBase ent in entities)
135 {
136 if (ent is SceneObjectGroup)
137 {
138 SceneObjectGroup sog = (SceneObjectGroup)ent;
139 sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
140 sog.ResumeScripts();
141 }
142 }
143 }
144
145 m_scripts_enabled = value;
146 }
147 }
148 }
149 private bool m_scripts_enabled;
79 150
80 public SynchronizeSceneHandler SynchronizeScene; 151 public SynchronizeSceneHandler SynchronizeScene;
81 152
@@ -284,8 +355,6 @@ namespace OpenSim.Region.Framework.Scenes
284 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 355 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
285 private Dictionary<UUID, int> m_groupsWithTargets = new Dictionary<UUID, int>(); 356 private Dictionary<UUID, int> m_groupsWithTargets = new Dictionary<UUID, int>();
286 357
287 private bool m_physics_enabled = true;
288 private bool m_scripts_enabled = true;
289 private string m_defaultScriptEngine; 358 private string m_defaultScriptEngine;
290 359
291 /// <summary> 360 /// <summary>
@@ -348,7 +417,6 @@ namespace OpenSim.Region.Framework.Scenes
348 417
349 private Timer m_mapGenerationTimer = new Timer(); 418 private Timer m_mapGenerationTimer = new Timer();
350 private bool m_generateMaptiles; 419 private bool m_generateMaptiles;
351 private bool m_useBackup = true;
352 420
353 #endregion Fields 421 #endregion Fields
354 422
@@ -614,11 +682,6 @@ namespace OpenSim.Region.Framework.Scenes
614 get { return m_authenticateHandler; } 682 get { return m_authenticateHandler; }
615 } 683 }
616 684
617 public bool UseBackup
618 {
619 get { return m_useBackup; }
620 }
621
622 // an instance to the physics plugin's Scene object. 685 // an instance to the physics plugin's Scene object.
623 public PhysicsScene PhysicsScene 686 public PhysicsScene PhysicsScene
624 { 687 {
@@ -678,7 +741,6 @@ namespace OpenSim.Region.Framework.Scenes
678 public Scene(RegionInfo regInfo, AgentCircuitManager authen, 741 public Scene(RegionInfo regInfo, AgentCircuitManager authen,
679 SceneCommunicationService sceneGridService, 742 SceneCommunicationService sceneGridService,
680 ISimulationDataService simDataService, IEstateDataService estateDataService, 743 ISimulationDataService simDataService, IEstateDataService estateDataService,
681 bool dumpAssetsToFile,
682 IConfigSource config, string simulatorVersion) 744 IConfigSource config, string simulatorVersion)
683 : this(regInfo) 745 : this(regInfo)
684 { 746 {
@@ -762,15 +824,20 @@ namespace OpenSim.Region.Framework.Scenes
762 // 824 //
763 // Out of memory 825 // Out of memory
764 // Operating system has killed the plugin 826 // Operating system has killed the plugin
765 m_sceneGraph.UnRecoverableError += RestartNow; 827 m_sceneGraph.UnRecoverableError
828 += () =>
829 {
830 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
831 RestartNow();
832 };
766 833
767 RegisterDefaultSceneEvents(); 834 RegisterDefaultSceneEvents();
768 835
769 DumpAssetsToFile = dumpAssetsToFile; 836 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled
770 837 // better in the future.
771 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; 838 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
772 839
773 m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics; 840 PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics;
774 841
775 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")"; 842 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")";
776 843
@@ -778,141 +845,154 @@ namespace OpenSim.Region.Framework.Scenes
778 845
779 // Region config overrides global config 846 // Region config overrides global config
780 // 847 //
781 try 848 if (m_config.Configs["Startup"] != null)
782 { 849 {
783 if (m_config.Configs["Startup"] != null) 850 IConfig startupConfig = m_config.Configs["Startup"];
851
852 StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
853
854 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
855 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
856 if (!UseBackup)
857 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
858
859 //Animation states
860 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
861
862 PhysicalPrims = startupConfig.GetBoolean("physical_prim", true);
863 CollidablePrims = startupConfig.GetBoolean("collidable_prim", true);
864
865 m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys);
866 if (RegionInfo.NonphysPrimMin > 0)
784 { 867 {
785 IConfig startupConfig = m_config.Configs["Startup"]; 868 m_minNonphys = RegionInfo.NonphysPrimMin;
869 }
786 870
787 StartDisabled = startupConfig.GetBoolean("StartDisabled", false); 871 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
872 if (RegionInfo.NonphysPrimMax > 0)
873 {
874 m_maxNonphys = RegionInfo.NonphysPrimMax;
875 }
788 876
789 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); 877 m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys);
790 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup); 878 if (RegionInfo.PhysPrimMin > 0)
791 if (!m_useBackup) 879 {
792 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); 880 m_minPhys = RegionInfo.PhysPrimMin;
793 881 }
794 //Animation states
795 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
796 882
797 PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); 883 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
798 CollidablePrims = startupConfig.GetBoolean("collidable_prim", true);
799 884
800 m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys); 885 if (RegionInfo.PhysPrimMax > 0)
801 if (RegionInfo.NonphysPrimMin > 0) 886 {
802 { 887 m_maxPhys = RegionInfo.PhysPrimMax;
803 m_minNonphys = RegionInfo.NonphysPrimMin; 888 }
804 }
805 889
806 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); 890 m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity);
807 if (RegionInfo.NonphysPrimMax > 0) 891 if (RegionInfo.LinksetCapacity > 0)
808 { 892 {
809 m_maxNonphys = RegionInfo.NonphysPrimMax; 893 m_linksetCapacity = RegionInfo.LinksetCapacity;
810 } 894 }
811 895
812 m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys); 896 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest");
813 if (RegionInfo.PhysPrimMin > 0) 897 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false);
814 {
815 m_minPhys = RegionInfo.PhysPrimMin;
816 }
817 898
818 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys); 899 // Here, if clamping is requested in either global or
900 // local config, it will be used
901 //
902 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize);
903 if (RegionInfo.ClampPrimSize)
904 {
905 m_clampPrimSize = true;
906 }
819 907
820 if (RegionInfo.PhysPrimMax > 0) 908 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete);
821 { 909 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
822 m_maxPhys = RegionInfo.PhysPrimMax; 910 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
823 } 911 m_dontPersistBefore =
912 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
913 m_dontPersistBefore *= 10000000;
914 m_persistAfter =
915 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
916 m_persistAfter *= 10000000;
824 917
825 m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity); 918 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
826 if (RegionInfo.LinksetCapacity > 0) 919 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
827 {
828 m_linksetCapacity = RegionInfo.LinksetCapacity;
829 }
830 920
831 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); 921 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
832 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); 922 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
923 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
833 924
834 // Here, if clamping is requested in either global or 925 string[] possibleMapConfigSections = new string[] { "Map", "Startup" };
835 // local config, it will be used 926
836 // 927 m_generateMaptiles
837 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize); 928 = Util.GetConfigVarFromSections<bool>(config, "GenerateMaptiles", possibleMapConfigSections, true);
838 if (RegionInfo.ClampPrimSize) 929
930 if (m_generateMaptiles)
931 {
932 int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0);
933 if (maptileRefresh != 0)
839 { 934 {
840 m_clampPrimSize = true; 935 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
936 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister;
937 m_mapGenerationTimer.AutoReset = true;
938 m_mapGenerationTimer.Start();
841 } 939 }
940 }
941 else
942 {
943 string tile
944 = Util.GetConfigVarFromSections<string>(
945 config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString());
842 946
843 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); 947 UUID tileID;
844 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); 948
845 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); 949 if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID))
846 m_dontPersistBefore =
847 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
848 m_dontPersistBefore *= 10000000;
849 m_persistAfter =
850 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
851 m_persistAfter *= 10000000;
852
853 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
854 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
855
856 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
857 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
858 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
859
860 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
861 if (m_generateMaptiles)
862 { 950 {
863 int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); 951 RegionInfo.RegionSettings.TerrainImageID = tileID;
864 if (maptileRefresh != 0)
865 {
866 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
867 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister;
868 m_mapGenerationTimer.AutoReset = true;
869 m_mapGenerationTimer.Start();
870 }
871 } 952 }
872 else 953 else
873 { 954 {
874 string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString()); 955 RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID;
875 UUID tileID; 956 m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString());
876
877 if (UUID.TryParse(tile, out tileID))
878 {
879 RegionInfo.RegionSettings.TerrainImageID = tileID;
880 }
881 } 957 }
958 }
959
960 string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "Startup" };
882 961
883 string grant = startupConfig.GetString("AllowedClients", String.Empty); 962 string grant
884 if (grant.Length > 0) 963 = Util.GetConfigVarFromSections<string>(
964 config, "AllowedClients", possibleAccessControlConfigSections, "");
965
966 if (grant.Length > 0)
967 {
968 foreach (string viewer in grant.Split(','))
885 { 969 {
886 foreach (string viewer in grant.Split(',')) 970 m_AllowedViewers.Add(viewer.Trim().ToLower());
887 {
888 m_AllowedViewers.Add(viewer.Trim().ToLower());
889 }
890 } 971 }
972 }
973
974 grant
975 = Util.GetConfigVarFromSections<string>(
976 config, "BannedClients", possibleAccessControlConfigSections, "");
891 977
892 grant = startupConfig.GetString("BannedClients", String.Empty); 978 if (grant.Length > 0)
893 if (grant.Length > 0) 979 {
980 foreach (string viewer in grant.Split(','))
894 { 981 {
895 foreach (string viewer in grant.Split(',')) 982 m_BannedViewers.Add(viewer.Trim().ToLower());
896 {
897 m_BannedViewers.Add(viewer.Trim().ToLower());
898 }
899 } 983 }
900
901 MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime);
902 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
903 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
904 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
905 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events);
906 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
907 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
908 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
909 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
910 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
911 } 984 }
912 } 985
913 catch (Exception e) 986 MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime);
914 { 987 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
915 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString()); 988 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
989 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
990 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events);
991 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
992 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
993 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
994 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
995 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
916 } 996 }
917 997
918 // FIXME: Ultimately this should be in a module. 998 // FIXME: Ultimately this should be in a module.
@@ -965,6 +1045,10 @@ namespace OpenSim.Region.Framework.Scenes
965 { 1045 {
966 PhysicalPrims = true; 1046 PhysicalPrims = true;
967 CollidablePrims = true; 1047 CollidablePrims = true;
1048 PhysicsEnabled = true;
1049
1050 PeriodicBackup = true;
1051 UseBackup = true;
968 1052
969 BordersLocked = true; 1053 BordersLocked = true;
970 Border northBorder = new Border(); 1054 Border northBorder = new Border();
@@ -1207,83 +1291,6 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1291 }
1208 } 1292 }
1209 1293
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() 1294 public int GetInaccurateNeighborCount()
1288 { 1295 {
1289 return m_neighbours.Count; 1296 return m_neighbours.Count;
@@ -1332,16 +1339,7 @@ namespace OpenSim.Region.Framework.Scenes
1332 1339
1333 m_log.Debug("[SCENE]: Persisting changed objects"); 1340 m_log.Debug("[SCENE]: Persisting changed objects");
1334 1341
1335 EntityBase[] entities = GetEntities(); 1342 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(); 1343 m_sceneGraph.Close();
1346 1344
1347 if (!GridService.DeregisterRegion(RegionInfo.RegionID)) 1345 if (!GridService.DeregisterRegion(RegionInfo.RegionID))
@@ -1568,7 +1566,7 @@ namespace OpenSim.Region.Framework.Scenes
1568 } 1566 }
1569 1567
1570 tmpMS = Util.EnvironmentTickCount(); 1568 tmpMS = Util.EnvironmentTickCount();
1571 if ((Frame % m_update_physics == 0) && m_physics_enabled) 1569 if (PhysicsEnabled && Frame % m_update_physics == 0)
1572 m_sceneGraph.UpdatePreparePhysics(); 1570 m_sceneGraph.UpdatePreparePhysics();
1573 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); 1571 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
1574 1572
@@ -1583,7 +1581,7 @@ namespace OpenSim.Region.Framework.Scenes
1583 tmpMS = Util.EnvironmentTickCount(); 1581 tmpMS = Util.EnvironmentTickCount();
1584 if (Frame % m_update_physics == 0) 1582 if (Frame % m_update_physics == 0)
1585 { 1583 {
1586 if (m_physics_enabled) 1584 if (PhysicsEnabled)
1587 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); 1585 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
1588 1586
1589 if (SynchronizeScene != null) 1587 if (SynchronizeScene != null)
@@ -1625,7 +1623,7 @@ namespace OpenSim.Region.Framework.Scenes
1625 eventMS = Util.EnvironmentTickCountSubtract(tmpMS); 1623 eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
1626 } 1624 }
1627 1625
1628 if (Frame % m_update_backup == 0) 1626 if (PeriodicBackup && Frame % m_update_backup == 0)
1629 { 1627 {
1630 tmpMS = Util.EnvironmentTickCount(); 1628 tmpMS = Util.EnvironmentTickCount();
1631 UpdateStorageBackup(); 1629 UpdateStorageBackup();
@@ -2646,7 +2644,6 @@ namespace OpenSim.Region.Framework.Scenes
2646 2644
2647 } 2645 }
2648 } 2646 }
2649
2650 2647
2651 return null; 2648 return null;
2652 } 2649 }
@@ -2769,8 +2766,6 @@ namespace OpenSim.Region.Framework.Scenes
2769 2766
2770 if (newPosition != Vector3.Zero) 2767 if (newPosition != Vector3.Zero)
2771 newObject.RootPart.GroupPosition = newPosition; 2768 newObject.RootPart.GroupPosition = newPosition;
2772 if (newObject.RootPart.KeyframeMotion != null)
2773 newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject);
2774 2769
2775 if (!AddSceneObject(newObject)) 2770 if (!AddSceneObject(newObject))
2776 { 2771 {
@@ -2798,6 +2793,9 @@ namespace OpenSim.Region.Framework.Scenes
2798 // before we restart the scripts, or else some functions won't work. 2793 // before we restart the scripts, or else some functions won't work.
2799 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); 2794 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
2800 newObject.ResumeScripts(); 2795 newObject.ResumeScripts();
2796
2797 if (newObject.RootPart.KeyframeMotion != null)
2798 newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject);
2801 } 2799 }
2802 2800
2803 // Do this as late as possible so that listeners have full access to the incoming object 2801 // Do this as late as possible so that listeners have full access to the incoming object
@@ -2863,9 +2861,12 @@ namespace OpenSim.Region.Framework.Scenes
2863// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); 2861// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
2864 2862
2865 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2863 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2866 2864
2865 // We must currently not resume scripts at this stage since AttachmentsModule does not have the
2866 // information that this is due to a teleport/border cross rather than an ordinary attachment.
2867 // We currently do this in Scene.MakeRootAgent() instead.
2867 if (AttachmentsModule != null) 2868 if (AttachmentsModule != null)
2868 AttachmentsModule.AttachObject(sp, grp, 0, false, false, false); 2869 AttachmentsModule.AttachObject(sp, grp, 0, false, false, false, true);
2869 } 2870 }
2870 else 2871 else
2871 { 2872 {
@@ -2970,24 +2971,16 @@ namespace OpenSim.Region.Framework.Scenes
2970 SubscribeToClientEvents(client); 2971 SubscribeToClientEvents(client);
2971 2972
2972 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); 2973 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2974 InventoryFolderBase cof = InventoryService.GetFolderForType(client.AgentId, (AssetType)46);
2975 if (cof == null)
2976 sp.COF = UUID.Zero;
2977 else
2978 sp.COF = cof.ID;
2979
2980 m_log.DebugFormat("[SCENE]: COF for {0} is {1}", client.AgentId, sp.COF);
2973 m_eventManager.TriggerOnNewPresence(sp); 2981 m_eventManager.TriggerOnNewPresence(sp);
2974 2982
2975 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; 2983 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2976
2977 // The first agent upon login is a root agent by design.
2978 // For this agent we will have to rez the attachments.
2979 // All other AddNewClient calls find aCircuit.child to be true.
2980 if (aCircuit.child == false)
2981 {
2982 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
2983 // start the scripts again (since this is done in RezAttachments()).
2984 // XXX: This is convoluted.
2985 sp.IsChildAgent = false;
2986 sp.IsLoggingIn = true;
2987
2988 if (AttachmentsModule != null)
2989 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
2990 }
2991 } 2984 }
2992 else 2985 else
2993 { 2986 {
@@ -3615,7 +3608,7 @@ namespace OpenSim.Region.Framework.Scenes
3615 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop 3608 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3616 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI 3609 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3617 if (closeChildAgents && CapsModule != null) 3610 if (closeChildAgents && CapsModule != null)
3618 CapsModule.RemoveCaps(agentID); 3611 CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode);
3619 3612
3620// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever 3613// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3621// // this method is doing is HORRIBLE!!! 3614// // this method is doing is HORRIBLE!!!
@@ -3846,20 +3839,36 @@ namespace OpenSim.Region.Framework.Scenes
3846 return false; 3839 return false;
3847 } 3840 }
3848 3841
3849
3850 ScenePresence sp = GetScenePresence(agent.AgentID); 3842 ScenePresence sp = GetScenePresence(agent.AgentID);
3851 3843
3852 if (sp != null && !sp.IsChildAgent) 3844 // If we have noo presence here or if that presence is a zombie root
3845 // presence that will be kicled, we need a new CAPS object.
3846 if (sp == null || (sp != null && !sp.IsChildAgent))
3853 { 3847 {
3854 // We have a zombie from a crashed session. 3848 if (CapsModule != null)
3855 // Or the same user is trying to be root twice here, won't work. 3849 {
3856 // Kill it. 3850 lock (agent)
3857 m_log.WarnFormat( 3851 {
3858 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", 3852 CapsModule.SetAgentCapsSeeds(agent);
3859 sp.Name, sp.UUID, RegionInfo.RegionName); 3853 CapsModule.CreateCaps(agent.AgentID, agent.circuitcode);
3854 }
3855 }
3856 }
3860 3857
3861 sp.ControllingClient.Close(true, true); 3858 if (sp != null)
3862 sp = null; 3859 {
3860 if (!sp.IsChildAgent)
3861 {
3862 // We have a zombie from a crashed session.
3863 // Or the same user is trying to be root twice here, won't work.
3864 // Kill it.
3865 m_log.WarnFormat(
3866 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3867 sp.Name, sp.UUID, RegionInfo.RegionName);
3868
3869 sp.ControllingClient.Close(true, true);
3870 sp = null;
3871 }
3863 } 3872 }
3864 3873
3865 lock (agent) 3874 lock (agent)
@@ -3900,7 +3909,9 @@ namespace OpenSim.Region.Framework.Scenes
3900 if (vialogin || (!m_seeIntoBannedRegion)) 3909 if (vialogin || (!m_seeIntoBannedRegion))
3901 { 3910 {
3902 if (!AuthorizeUser(agent, out reason)) 3911 if (!AuthorizeUser(agent, out reason))
3912 {
3903 return false; 3913 return false;
3914 }
3904 } 3915 }
3905 } 3916 }
3906 catch (Exception e) 3917 catch (Exception e)
@@ -3915,11 +3926,6 @@ namespace OpenSim.Region.Framework.Scenes
3915 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, 3926 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3916 agent.AgentID, agent.circuitcode); 3927 agent.AgentID, agent.circuitcode);
3917 3928
3918 if (CapsModule != null)
3919 {
3920 CapsModule.SetAgentCapsSeeds(agent);
3921 CapsModule.CreateCaps(agent.AgentID);
3922 }
3923 } 3929 }
3924 else 3930 else
3925 { 3931 {
@@ -3945,6 +3951,11 @@ namespace OpenSim.Region.Framework.Scenes
3945 agent.teleportFlags = teleportFlags; 3951 agent.teleportFlags = teleportFlags;
3946 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 3952 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
3947 3953
3954 if (CapsModule != null)
3955 {
3956 CapsModule.ActivateCaps(agent.circuitcode);
3957 }
3958
3948 if (vialogin) 3959 if (vialogin)
3949 { 3960 {
3950// CleanDroppedAttachments(); 3961// CleanDroppedAttachments();
@@ -4306,33 +4317,33 @@ namespace OpenSim.Region.Framework.Scenes
4306// } 4317// }
4307// } 4318// }
4308 4319
4309 /// <summary> 4320// /// <summary>
4310 /// Triggered when an agent crosses into this sim. Also happens on initial login. 4321// /// Triggered when an agent crosses into this sim. Also happens on initial login.
4311 /// </summary> 4322// /// </summary>
4312 /// <param name="agentID"></param> 4323// /// <param name="agentID"></param>
4313 /// <param name="position"></param> 4324// /// <param name="position"></param>
4314 /// <param name="isFlying"></param> 4325// /// <param name="isFlying"></param>
4315 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) 4326// public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
4316 { 4327// {
4317 ScenePresence presence = GetScenePresence(agentID); 4328// ScenePresence presence = GetScenePresence(agentID);
4318 if (presence != null) 4329// if (presence != null)
4319 { 4330// {
4320 try 4331// try
4321 { 4332// {
4322 presence.MakeRootAgent(position, isFlying); 4333// presence.MakeRootAgent(position, isFlying);
4323 } 4334// }
4324 catch (Exception e) 4335// catch (Exception e)
4325 { 4336// {
4326 m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace); 4337// m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
4327 } 4338// }
4328 } 4339// }
4329 else 4340// else
4330 { 4341// {
4331 m_log.ErrorFormat( 4342// m_log.ErrorFormat(
4332 "[SCENE]: Could not find presence for agent {0} crossing into scene {1}", 4343// "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
4333 agentID, RegionInfo.RegionName); 4344// agentID, RegionInfo.RegionName);
4334 } 4345// }
4335 } 4346// }
4336 4347
4337 /// <summary> 4348 /// <summary>
4338 /// We've got an update about an agent that sees into this region, 4349 /// We've got an update about an agent that sees into this region,
@@ -4702,19 +4713,6 @@ namespace OpenSim.Region.Framework.Scenes
4702 4713
4703 #region Script Engine 4714 #region Script Engine
4704 4715
4705 private List<ScriptEngineInterface> ScriptEngines = new List<ScriptEngineInterface>();
4706 public bool DumpAssetsToFile;
4707
4708 /// <summary>
4709 ///
4710 /// </summary>
4711 /// <param name="scriptEngine"></param>
4712 public void AddScriptEngine(ScriptEngineInterface scriptEngine)
4713 {
4714 ScriptEngines.Add(scriptEngine);
4715 scriptEngine.InitializeEngine(this);
4716 }
4717
4718 private bool ScriptDanger(SceneObjectPart part,Vector3 pos) 4716 private bool ScriptDanger(SceneObjectPart part,Vector3 pos)
4719 { 4717 {
4720 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); 4718 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
@@ -5122,7 +5120,7 @@ namespace OpenSim.Region.Framework.Scenes
5122 { 5120 {
5123 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) 5121 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
5124 { 5122 {
5125 if (grp.RootPart.Expires <= DateTime.Now) 5123 if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= DateTime.Now)
5126 DeleteSceneObject(grp, false); 5124 DeleteSceneObject(grp, false);
5127 } 5125 }
5128 } 5126 }
@@ -5621,33 +5619,7 @@ Environment.Exit(1);
5621 5619
5622 public void TriggerEstateSunUpdate() 5620 public void TriggerEstateSunUpdate()
5623 { 5621 {
5624 float sun; 5622 EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
5625 if (RegionInfo.RegionSettings.UseEstateSun)
5626 {
5627 sun = (float)RegionInfo.EstateSettings.SunPosition;
5628 if (RegionInfo.EstateSettings.UseGlobalTime)
5629 {
5630 sun = EventManager.GetCurrentTimeAsSunLindenHour() - 6.0f;
5631 }
5632
5633 //
5634 EventManager.TriggerEstateToolsSunUpdate(
5635 RegionInfo.RegionHandle,
5636 RegionInfo.EstateSettings.FixedSun,
5637 RegionInfo.RegionSettings.UseEstateSun,
5638 sun);
5639 }
5640 else
5641 {
5642 // Use the Sun Position from the Region Settings
5643 sun = (float)RegionInfo.RegionSettings.SunPosition - 6.0f;
5644
5645 EventManager.TriggerEstateToolsSunUpdate(
5646 RegionInfo.RegionHandle,
5647 RegionInfo.RegionSettings.FixedSun,
5648 RegionInfo.RegionSettings.UseEstateSun,
5649 sun);
5650 }
5651 } 5623 }
5652 5624
5653 private void HandleReloadEstate(string module, string[] cmd) 5625 private void HandleReloadEstate(string module, string[] cmd)
@@ -5915,8 +5887,13 @@ Environment.Exit(1);
5915 5887
5916 if (banned) 5888 if (banned)
5917 { 5889 {
5918 reason = "No suitable landing point found"; 5890 if(Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
5919 return false; 5891 {
5892 reason = "No suitable landing point found";
5893 return false;
5894 }
5895 reason = "Administrative access only";
5896 return true;
5920 } 5897 }
5921 } 5898 }
5922 } 5899 }
@@ -6043,10 +6020,17 @@ Environment.Exit(1);
6043 GC.Collect(); 6020 GC.Collect();
6044 } 6021 }
6045 6022
6046 // Wrappers to get physics modules retrieve assets. Has to be done this way 6023 /// <summary>
6047 // because we can't assign the asset service to physics directly - at the 6024 /// Wrappers to get physics modules retrieve assets.
6048 // time physics are instantiated it's not registered but it will be by 6025 /// </summary>
6049 // the time the first prim exists. 6026 /// <remarks>
6027 /// Has to be done this way
6028 /// because we can't assign the asset service to physics directly - at the
6029 /// time physics are instantiated it's not registered but it will be by
6030 /// the time the first prim exists.
6031 /// </remarks>
6032 /// <param name="assetID"></param>
6033 /// <param name="callback"></param>
6050 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) 6034 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
6051 { 6035 {
6052 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); 6036 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index 0e0b6c3..c70342f 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -100,7 +100,6 @@ namespace OpenSim.Region.Framework.Scenes
100 } 100 }
101 101
102 private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>(); 102 private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>();
103 private Scene m_currentScene = null;
104 103
105 public List<Scene> Scenes 104 public List<Scene> Scenes
106 { 105 {
@@ -313,35 +312,30 @@ namespace OpenSim.Region.Framework.Scenes
313 312
314 public void SendCommandToPluginModules(string[] cmdparams) 313 public void SendCommandToPluginModules(string[] cmdparams)
315 { 314 {
316 ForEachCurrentScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); }); 315 ForEachSelectedScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); });
317 } 316 }
318 317
319 public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions) 318 public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions)
320 { 319 {
321 ForEachCurrentScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); }); 320 ForEachSelectedScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); });
322 } 321 }
323 322
324 private void ForEachCurrentScene(Action<Scene> func) 323 public void ForEachSelectedScene(Action<Scene> func)
325 { 324 {
326 if (CurrentScene == null) 325 if (CurrentScene == null)
327 { 326 ForEachScene(func);
328 List<Scene> sceneList = Scenes;
329 sceneList.ForEach(func);
330 }
331 else 327 else
332 {
333 func(CurrentScene); 328 func(CurrentScene);
334 }
335 } 329 }
336 330
337 public void RestartCurrentScene() 331 public void RestartCurrentScene()
338 { 332 {
339 ForEachCurrentScene(delegate(Scene scene) { scene.RestartNow(); }); 333 ForEachSelectedScene(delegate(Scene scene) { scene.RestartNow(); });
340 } 334 }
341 335
342 public void BackupCurrentScene() 336 public void BackupCurrentScene()
343 { 337 {
344 ForEachCurrentScene(delegate(Scene scene) { scene.Backup(true); }); 338 ForEachSelectedScene(delegate(Scene scene) { scene.Backup(true); });
345 } 339 }
346 340
347 public bool TrySetCurrentScene(string regionName) 341 public bool TrySetCurrentScene(string regionName)
@@ -359,7 +353,7 @@ namespace OpenSim.Region.Framework.Scenes
359 353
360 if (m_localScenes.TryGetValue(regionName, out s)) 354 if (m_localScenes.TryGetValue(regionName, out s))
361 { 355 {
362 m_currentScene = s; 356 CurrentScene = s;
363 return true; 357 return true;
364 } 358 }
365 359
@@ -375,7 +369,7 @@ namespace OpenSim.Region.Framework.Scenes
375 369
376 if (m_localScenes.TryGetValue(regionID, out s)) 370 if (m_localScenes.TryGetValue(regionID, out s))
377 { 371 {
378 m_currentScene = s; 372 CurrentScene = s;
379 return true; 373 return true;
380 } 374 }
381 375
@@ -434,7 +428,7 @@ namespace OpenSim.Region.Framework.Scenes
434 /// <param name="name">Name of avatar to debug</param> 428 /// <param name="name">Name of avatar to debug</param>
435 public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name) 429 public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name)
436 { 430 {
437 ForEachCurrentScene(scene => 431 ForEachSelectedScene(scene =>
438 scene.ForEachScenePresence(sp => 432 scene.ForEachScenePresence(sp =>
439 { 433 {
440 if (name == null || sp.Name == name) 434 if (name == null || sp.Name == name)
@@ -453,7 +447,7 @@ namespace OpenSim.Region.Framework.Scenes
453 { 447 {
454 List<ScenePresence> avatars = new List<ScenePresence>(); 448 List<ScenePresence> avatars = new List<ScenePresence>();
455 449
456 ForEachCurrentScene( 450 ForEachSelectedScene(
457 delegate(Scene scene) 451 delegate(Scene scene)
458 { 452 {
459 scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) 453 scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -470,7 +464,7 @@ namespace OpenSim.Region.Framework.Scenes
470 { 464 {
471 List<ScenePresence> presences = new List<ScenePresence>(); 465 List<ScenePresence> presences = new List<ScenePresence>();
472 466
473 ForEachCurrentScene(delegate(Scene scene) 467 ForEachSelectedScene(delegate(Scene scene)
474 { 468 {
475 scene.ForEachScenePresence(delegate(ScenePresence sp) 469 scene.ForEachScenePresence(delegate(ScenePresence sp)
476 { 470 {
@@ -494,12 +488,12 @@ namespace OpenSim.Region.Framework.Scenes
494 488
495 public void ForceCurrentSceneClientUpdate() 489 public void ForceCurrentSceneClientUpdate()
496 { 490 {
497 ForEachCurrentScene(delegate(Scene scene) { scene.ForceClientUpdate(); }); 491 ForEachSelectedScene(delegate(Scene scene) { scene.ForceClientUpdate(); });
498 } 492 }
499 493
500 public void HandleEditCommandOnCurrentScene(string[] cmdparams) 494 public void HandleEditCommandOnCurrentScene(string[] cmdparams)
501 { 495 {
502 ForEachCurrentScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); }); 496 ForEachSelectedScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); });
503 } 497 }
504 498
505 public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) 499 public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar)
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index 26524fb..f8624e7 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -34,6 +34,7 @@ using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using System.Collections.Generic; 35using System.Collections.Generic;
36using System.Xml; 36using System.Xml;
37using PermissionMask = OpenSim.Framework.PermissionMask;
37 38
38namespace OpenSim.Region.Framework.Scenes 39namespace OpenSim.Region.Framework.Scenes
39{ 40{
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index ed1bbd8..69fb6df 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -41,6 +41,7 @@ using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Physics.Manager; 42using OpenSim.Region.Physics.Manager;
43using OpenSim.Region.Framework.Scenes.Serialization; 43using OpenSim.Region.Framework.Scenes.Serialization;
44using PermissionMask = OpenSim.Framework.PermissionMask;
44 45
45namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
46{ 47{
@@ -101,6 +102,15 @@ namespace OpenSim.Region.Framework.Scenes
101 /// </summary> 102 /// </summary>
102 public partial class SceneObjectGroup : EntityBase, ISceneObject 103 public partial class SceneObjectGroup : EntityBase, ISceneObject
103 { 104 {
105 // Axis selection bitmask used by SetAxisRotation()
106 // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
107 public enum axisSelect : int
108 {
109 STATUS_ROTATE_X = 0x002,
110 STATUS_ROTATE_Y = 0x004,
111 STATUS_ROTATE_Z = 0x008,
112 }
113
104 // private PrimCountTaintedDelegate handlerPrimCountTainted = null; 114 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
105 115
106 /// <summary> 116 /// <summary>
@@ -512,11 +522,19 @@ namespace OpenSim.Region.Framework.Scenes
512 522
513 if (Scene != null) 523 if (Scene != null)
514 { 524 {
515 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 525 if (
516 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 526 // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E)
517 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 527 // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
518 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W) 528 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N)
519 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S)) 529 // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
530 // Experimental change for better border crossings.
531 // The commented out original lines above would, it seems, trigger
532 // a border crossing a little early or late depending on which
533 // direction the object was moving.
534 (Scene.TestBorderCross(val, Cardinals.E)
535 || Scene.TestBorderCross(val, Cardinals.W)
536 || Scene.TestBorderCross(val, Cardinals.N)
537 || Scene.TestBorderCross(val, Cardinals.S))
520 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 538 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
521 { 539 {
522 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 540 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
@@ -935,6 +953,18 @@ namespace OpenSim.Region.Framework.Scenes
935 /// </remarks> 953 /// </remarks>
936 public UUID FromFolderID { get; set; } 954 public UUID FromFolderID { get; set; }
937 955
956 /// <summary>
957 /// IDs of all avatars sat on this scene object.
958 /// </summary>
959 /// <remarks>
960 /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
961 /// This must be locked before it is read or written.
962 /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
963 /// No avatar should appear more than once in this list.
964 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
965 /// </remarks>
966 protected internal List<UUID> m_sittingAvatars = new List<UUID>();
967
938 #endregion 968 #endregion
939 969
940// ~SceneObjectGroup() 970// ~SceneObjectGroup()
@@ -3438,7 +3468,7 @@ namespace OpenSim.Region.Framework.Scenes
3438 3468
3439 public void AdjustChildPrimPermissions() 3469 public void AdjustChildPrimPermissions()
3440 { 3470 {
3441 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits 3471 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits
3442 uint foldedPerms = RootPart.OwnerMask & 3; 3472 uint foldedPerms = RootPart.OwnerMask & 3;
3443 3473
3444 ForEachPart(part => 3474 ForEachPart(part =>
@@ -4509,17 +4539,28 @@ namespace OpenSim.Region.Framework.Scenes
4509 } 4539 }
4510 4540
4511 /// <summary> 4541 /// <summary>
4542 /// Get a copy of the list of sitting avatars on all prims of this object.
4543 /// </summary>
4544 /// <remarks>
4545 /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
4546 /// down after it move one place down the list.
4547 /// </remarks>
4548 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
4549 public List<UUID> GetSittingAvatars()
4550 {
4551 lock (m_sittingAvatars)
4552 return new List<UUID>(m_sittingAvatars);
4553 }
4554
4555 /// <summary>
4512 /// Gets the number of sitting avatars. 4556 /// Gets the number of sitting avatars.
4513 /// </summary> 4557 /// </summary>
4514 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> 4558 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4515 /// <returns></returns> 4559 /// <returns></returns>
4516 public int GetSittingAvatarsCount() 4560 public int GetSittingAvatarsCount()
4517 { 4561 {
4518 int count = 0; 4562 lock (m_sittingAvatars)
4519 4563 return m_sittingAvatars.Count;
4520 Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount());
4521
4522 return count;
4523 } 4564 }
4524 4565
4525 public override string ToString() 4566 public override string ToString()
@@ -4528,7 +4569,7 @@ namespace OpenSim.Region.Framework.Scenes
4528 } 4569 }
4529 4570
4530 #region ISceneObject 4571 #region ISceneObject
4531 4572
4532 public virtual ISceneObject CloneForNewScene() 4573 public virtual ISceneObject CloneForNewScene()
4533 { 4574 {
4534 SceneObjectGroup sog = Copy(false); 4575 SceneObjectGroup sog = Copy(false);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 8528edc..42644dc 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -37,11 +37,13 @@ using System.Xml.Serialization;
37using log4net; 37using log4net;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
40using OpenSim.Framework; 41using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes.Scripting; 43using OpenSim.Region.Framework.Scenes.Scripting;
43using OpenSim.Region.Framework.Scenes.Serialization; 44using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Region.Physics.Manager; 45using OpenSim.Region.Physics.Manager;
46using PermissionMask = OpenSim.Framework.PermissionMask;
45 47
46namespace OpenSim.Region.Framework.Scenes 48namespace OpenSim.Region.Framework.Scenes
47{ 49{
@@ -116,7 +118,7 @@ namespace OpenSim.Region.Framework.Scenes
116 118
117 #endregion Enumerations 119 #endregion Enumerations
118 120
119 public class SceneObjectPart : IScriptHost, ISceneEntity 121 public class SceneObjectPart : ISceneEntity
120 { 122 {
121 /// <value> 123 /// <value>
122 /// Denote all sides of the prim 124 /// Denote all sides of the prim
@@ -136,6 +138,32 @@ namespace OpenSim.Region.Framework.Scenes
136 138
137 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 139 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
138 140
141 /// <summary>
142 /// Dynamic attributes can be created and deleted as required.
143 /// </summary>
144 public DAMap DynAttrs { get; set; }
145
146 private DOMap m_dynObjs;
147
148 /// <summary>
149 /// Dynamic objects that can be created and deleted as required.
150 /// </summary>
151 public DOMap DynObjs
152 {
153 get
154 {
155 if (m_dynObjs == null)
156 m_dynObjs = new DOMap();
157
158 return m_dynObjs;
159 }
160
161 set
162 {
163 m_dynObjs = value;
164 }
165 }
166
139 /// <value> 167 /// <value>
140 /// Is this a root part? 168 /// Is this a root part?
141 /// </value> 169 /// </value>
@@ -386,6 +414,7 @@ namespace OpenSim.Region.Framework.Scenes
386 m_particleSystem = Utils.EmptyBytes; 414 m_particleSystem = Utils.EmptyBytes;
387 Rezzed = DateTime.UtcNow; 415 Rezzed = DateTime.UtcNow;
388 Description = String.Empty; 416 Description = String.Empty;
417 DynAttrs = new DAMap();
389 418
390 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, 419 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol,
391 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from 420 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from
@@ -441,8 +470,8 @@ namespace OpenSim.Region.Framework.Scenes
441 private uint _category; 470 private uint _category;
442 private Int32 _creationDate; 471 private Int32 _creationDate;
443 private uint _parentID = 0; 472 private uint _parentID = 0;
444 private uint _baseMask = (uint)PermissionMask.All; 473 private uint _baseMask = (uint)(PermissionMask.All | PermissionMask.Export);
445 private uint _ownerMask = (uint)PermissionMask.All; 474 private uint _ownerMask = (uint)(PermissionMask.All | PermissionMask.Export);
446 private uint _groupMask = (uint)PermissionMask.None; 475 private uint _groupMask = (uint)PermissionMask.None;
447 private uint _everyoneMask = (uint)PermissionMask.None; 476 private uint _everyoneMask = (uint)PermissionMask.None;
448 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer); 477 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
@@ -1342,7 +1371,7 @@ namespace OpenSim.Region.Framework.Scenes
1342 public UUID SitTargetAvatar { get; set; } 1371 public UUID SitTargetAvatar { get; set; }
1343 1372
1344 /// <summary> 1373 /// <summary>
1345 /// IDs of all avatars start on this object part. 1374 /// IDs of all avatars sat on this part.
1346 /// </summary> 1375 /// </summary>
1347 /// <remarks> 1376 /// <remarks>
1348 /// We need to track this so that we can stop sat upon prims from being attached. 1377 /// We need to track this so that we can stop sat upon prims from being attached.
@@ -1689,6 +1718,10 @@ namespace OpenSim.Region.Framework.Scenes
1689 1718
1690 if (ParentGroup != null) 1719 if (ParentGroup != null)
1691 ParentGroup.HasGroupChanged = true; 1720 ParentGroup.HasGroupChanged = true;
1721
1722 PhysicsActor pa = PhysActor;
1723 if (pa != null)
1724 pa.Density = Density;
1692 } 1725 }
1693 } 1726 }
1694 1727
@@ -1708,6 +1741,9 @@ namespace OpenSim.Region.Framework.Scenes
1708 if (ParentGroup != null) 1741 if (ParentGroup != null)
1709 ParentGroup.HasGroupChanged = true; 1742 ParentGroup.HasGroupChanged = true;
1710 1743
1744 PhysicsActor pa = PhysActor;
1745 if (pa != null)
1746 pa.GravModifier = GravityModifier;
1711 } 1747 }
1712 } 1748 }
1713 1749
@@ -1726,10 +1762,14 @@ namespace OpenSim.Region.Framework.Scenes
1726 1762
1727 if (ParentGroup != null) 1763 if (ParentGroup != null)
1728 ParentGroup.HasGroupChanged = true; 1764 ParentGroup.HasGroupChanged = true;
1765
1766 PhysicsActor pa = PhysActor;
1767 if (pa != null)
1768 pa.Friction = Friction;
1729 } 1769 }
1730 } 1770 }
1731 1771
1732 public float Bounciness 1772 public float Restitution
1733 { 1773 {
1734 get { return m_bounce; } 1774 get { return m_bounce; }
1735 set 1775 set
@@ -1744,6 +1784,10 @@ namespace OpenSim.Region.Framework.Scenes
1744 1784
1745 if (ParentGroup != null) 1785 if (ParentGroup != null)
1746 ParentGroup.HasGroupChanged = true; 1786 ParentGroup.HasGroupChanged = true;
1787
1788 PhysicsActor pa = PhysActor;
1789 if (pa != null)
1790 pa.Restitution = Restitution;
1747 } 1791 }
1748 } 1792 }
1749 1793
@@ -2118,6 +2162,8 @@ namespace OpenSim.Region.Framework.Scenes
2118 // safeguard actual copy is done in sog.copy 2162 // safeguard actual copy is done in sog.copy
2119 dupe.KeyframeMotion = null; 2163 dupe.KeyframeMotion = null;
2120 2164
2165 dupe.DynAttrs.CopyFrom(DynAttrs);
2166
2121 if (userExposed) 2167 if (userExposed)
2122 { 2168 {
2123/* 2169/*
@@ -2431,11 +2477,11 @@ namespace OpenSim.Region.Framework.Scenes
2431 public int GetAxisRotation(int axis) 2477 public int GetAxisRotation(int axis)
2432 { 2478 {
2433 //Cannot use ScriptBaseClass constants as no referance to it currently. 2479 //Cannot use ScriptBaseClass constants as no referance to it currently.
2434 if (axis == 2)//STATUS_ROTATE_X 2480 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
2435 return STATUS_ROTATE_X; 2481 return STATUS_ROTATE_X;
2436 if (axis == 4)//STATUS_ROTATE_Y 2482 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
2437 return STATUS_ROTATE_Y; 2483 return STATUS_ROTATE_Y;
2438 if (axis == 8)//STATUS_ROTATE_Z 2484 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
2439 return STATUS_ROTATE_Z; 2485 return STATUS_ROTATE_Z;
2440 2486
2441 return 0; 2487 return 0;
@@ -2470,18 +2516,6 @@ namespace OpenSim.Region.Framework.Scenes
2470 return new Vector3(0, 0, 0); 2516 return new Vector3(0, 0, 0);
2471 2517
2472 return ParentGroup.GetGeometricCenter(); 2518 return ParentGroup.GetGeometricCenter();
2473
2474 /*
2475 PhysicsActor pa = PhysActor;
2476
2477 if (pa != null)
2478 {
2479 Vector3 vtmp = pa.CenterOfMass;
2480 return vtmp;
2481 }
2482 else
2483 return new Vector3(0, 0, 0);
2484 */
2485 } 2519 }
2486 2520
2487 public float GetMass() 2521 public float GetMass()
@@ -2895,11 +2929,14 @@ namespace OpenSim.Region.Framework.Scenes
2895 2929
2896 public void PhysicsOutOfBounds(Vector3 pos) 2930 public void PhysicsOutOfBounds(Vector3 pos)
2897 { 2931 {
2898 m_log.Error("[PHYSICS]: Physical Object went out of bounds."); 2932 // Note: This is only being called on the root prim at this time.
2933
2934 m_log.ErrorFormat(
2935 "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.",
2936 Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition);
2899 2937
2900 RemFlag(PrimFlags.Physics); 2938 RemFlag(PrimFlags.Physics);
2901 DoPhysicsPropertyUpdate(false, true); 2939 DoPhysicsPropertyUpdate(false, true);
2902 //ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2903 } 2940 }
2904 2941
2905 public void PhysicsRequestingTerseUpdate() 2942 public void PhysicsRequestingTerseUpdate()
@@ -3322,13 +3359,13 @@ namespace OpenSim.Region.Framework.Scenes
3322 ParentGroup.SetAxisRotation(axis, rotate); 3359 ParentGroup.SetAxisRotation(axis, rotate);
3323 3360
3324 //Cannot use ScriptBaseClass constants as no referance to it currently. 3361 //Cannot use ScriptBaseClass constants as no referance to it currently.
3325 if (axis == 2)//STATUS_ROTATE_X 3362 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
3326 STATUS_ROTATE_X = rotate; 3363 STATUS_ROTATE_X = rotate;
3327 3364
3328 if (axis == 4)//STATUS_ROTATE_Y 3365 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
3329 STATUS_ROTATE_Y = rotate; 3366 STATUS_ROTATE_Y = rotate;
3330 3367
3331 if (axis == 8)//STATUS_ROTATE_Z 3368 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
3332 STATUS_ROTATE_Z = rotate; 3369 STATUS_ROTATE_Z = rotate;
3333 } 3370 }
3334 3371
@@ -3706,6 +3743,10 @@ namespace OpenSim.Region.Framework.Scenes
3706 /// <param name="events"></param> 3743 /// <param name="events"></param>
3707 public void SetScriptEvents(UUID scriptid, int events) 3744 public void SetScriptEvents(UUID scriptid, int events)
3708 { 3745 {
3746// m_log.DebugFormat(
3747// "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}",
3748// scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name);
3749
3709 // scriptEvents oldparts; 3750 // scriptEvents oldparts;
3710 lock (m_scriptEvents) 3751 lock (m_scriptEvents)
3711 { 3752 {
@@ -4235,6 +4276,7 @@ namespace OpenSim.Region.Framework.Scenes
4235 result.distance = distance2; 4276 result.distance = distance2;
4236 result.HitTF = true; 4277 result.HitTF = true;
4237 result.ipoint = q; 4278 result.ipoint = q;
4279 result.face = i;
4238 //m_log.Info("[FACE]:" + i.ToString()); 4280 //m_log.Info("[FACE]:" + i.ToString());
4239 //m_log.Info("[POINT]: " + q.ToString()); 4281 //m_log.Info("[POINT]: " + q.ToString());
4240 //m_log.Info("[DIST]: " + distance2.ToString()); 4282 //m_log.Info("[DIST]: " + distance2.ToString());
@@ -4281,10 +4323,10 @@ namespace OpenSim.Region.Framework.Scenes
4281 4323
4282 public void TrimPermissions() 4324 public void TrimPermissions()
4283 { 4325 {
4284 BaseMask &= (uint)PermissionMask.All; 4326 BaseMask &= (uint)(PermissionMask.All | PermissionMask.Export);
4285 OwnerMask &= (uint)PermissionMask.All; 4327 OwnerMask &= (uint)(PermissionMask.All | PermissionMask.Export);
4286 GroupMask &= (uint)PermissionMask.All; 4328 GroupMask &= (uint)PermissionMask.All;
4287 EveryoneMask &= (uint)PermissionMask.All; 4329 EveryoneMask &= (uint)(PermissionMask.All | PermissionMask.Export);
4288 NextOwnerMask &= (uint)PermissionMask.All; 4330 NextOwnerMask &= (uint)PermissionMask.All;
4289 } 4331 }
4290 4332
@@ -4387,10 +4429,22 @@ namespace OpenSim.Region.Framework.Scenes
4387 baseMask; 4429 baseMask;
4388 break; 4430 break;
4389 case 8: 4431 case 8:
4432 // Trying to set export permissions - extra checks
4433 if (set && (mask & (uint)PermissionMask.Export) != 0)
4434 {
4435 if ((OwnerMask & (uint)PermissionMask.Export) == 0 || (BaseMask & (uint)PermissionMask.Export) == 0 || (NextOwnerMask & (uint)PermissionMask.All) != (uint)PermissionMask.All)
4436 mask &= ~(uint)PermissionMask.Export;
4437 }
4390 EveryoneMask = ApplyMask(EveryoneMask, set, mask) & 4438 EveryoneMask = ApplyMask(EveryoneMask, set, mask) &
4391 baseMask; 4439 baseMask;
4392 break; 4440 break;
4393 case 16: 4441 case 16:
4442 // Force full perm if export
4443 if ((EveryoneMask & (uint)PermissionMask.Export) != 0)
4444 {
4445 NextOwnerMask = (uint)PermissionMask.All;
4446 break;
4447 }
4394 NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) & 4448 NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) &
4395 baseMask; 4449 baseMask;
4396 // Prevent the client from creating no copy, no transfer 4450 // Prevent the client from creating no copy, no transfer
@@ -4493,8 +4547,8 @@ namespace OpenSim.Region.Framework.Scenes
4493 GravityModifier = physdata.GravitationModifier; 4547 GravityModifier = physdata.GravitationModifier;
4494 if(Friction != physdata.Friction) 4548 if(Friction != physdata.Friction)
4495 Friction = physdata.Friction; 4549 Friction = physdata.Friction;
4496 if(Bounciness != physdata.Bounce) 4550 if(Restitution != physdata.Bounce)
4497 Bounciness = physdata.Bounce; 4551 Restitution = physdata.Bounce;
4498 } 4552 }
4499 /// <summary> 4553 /// <summary>
4500 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. 4554 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
@@ -4558,7 +4612,8 @@ namespace OpenSim.Region.Framework.Scenes
4558 if (ParentGroup.RootPart == this) 4612 if (ParentGroup.RootPart == this)
4559 AngularVelocity = new Vector3(0, 0, 0); 4613 AngularVelocity = new Vector3(0, 0, 0);
4560 } 4614 }
4561 else 4615
4616 else
4562 { 4617 {
4563 if (ParentGroup.Scene.CollidablePrims) 4618 if (ParentGroup.Scene.CollidablePrims)
4564 { 4619 {
@@ -4604,9 +4659,31 @@ namespace OpenSim.Region.Framework.Scenes
4604 UpdatePhysicsSubscribedEvents(); 4659 UpdatePhysicsSubscribedEvents();
4605 } 4660 }
4606 } 4661 }
4607 4662 if (SetVD)
4663 {
4664 // If the above logic worked (this is urgent candidate to unit tests!)
4665 // we now have a physicsactor.
4666 // Defensive programming calls for a check here.
4667 // Better would be throwing an exception that could be catched by a unit test as the internal
4668 // logic should make sure, this Physactor is always here.
4669 if (pa != null)
4670 {
4671 pa.SetVolumeDetect(1);
4672 AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active
4673 VolumeDetectActive = true;
4674 }
4608 // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); 4675 // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString());
4676 }
4677 else if (SetVD != wasVD)
4678 {
4679 // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like
4680 // (mumbles, well, at least if you have infinte CPU powers :-))
4681 if (pa != null)
4682 pa.SetVolumeDetect(0);
4609 4683
4684 RemFlag(PrimFlags.Phantom);
4685 VolumeDetectActive = false;
4686 }
4610 // and last in case we have a new actor and not building 4687 // and last in case we have a new actor and not building
4611 4688
4612 if (ParentGroup != null) 4689 if (ParentGroup != null)
@@ -4646,9 +4723,9 @@ namespace OpenSim.Region.Framework.Scenes
4646 PhysicsShapeType, 4723 PhysicsShapeType,
4647 m_localId); 4724 m_localId);
4648 } 4725 }
4649 catch (Exception ex) 4726 catch (Exception e)
4650 { 4727 {
4651 m_log.ErrorFormat("[SCENE]: AddToPhysics object {0} failed: {1}", m_uuid, ex.Message); 4728 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom. e={1}", m_uuid, e);
4652 pa = null; 4729 pa = null;
4653 } 4730 }
4654 4731
@@ -4657,6 +4734,11 @@ namespace OpenSim.Region.Framework.Scenes
4657 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info 4734 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info
4658 pa.SetMaterial(Material); 4735 pa.SetMaterial(Material);
4659 4736
4737 pa.Density = Density;
4738 pa.GravModifier = GravityModifier;
4739 pa.Friction = Friction;
4740 pa.Restitution = Restitution;
4741
4660 if (VolumeDetectActive) // change if not the default only 4742 if (VolumeDetectActive) // change if not the default only
4661 pa.SetVolumeDetect(1); 4743 pa.SetVolumeDetect(1);
4662 4744
@@ -4717,7 +4799,9 @@ namespace OpenSim.Region.Framework.Scenes
4717 } 4799 }
4718 4800
4719 PhysActor = pa; 4801 PhysActor = pa;
4720 } 4802
4803 ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
4804 }
4721 4805
4722 /// <summary> 4806 /// <summary>
4723 /// This removes the part from the physics scene. 4807 /// This removes the part from the physics scene.
@@ -4736,6 +4820,8 @@ namespace OpenSim.Region.Framework.Scenes
4736 pa.OnOutOfBounds -= PhysicsOutOfBounds; 4820 pa.OnOutOfBounds -= PhysicsOutOfBounds;
4737 4821
4738 ParentGroup.Scene.PhysicsScene.RemovePrim(pa); 4822 ParentGroup.Scene.PhysicsScene.RemovePrim(pa);
4823
4824 ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
4739 } 4825 }
4740 PhysActor = null; 4826 PhysActor = null;
4741 } 4827 }
@@ -4911,8 +4997,25 @@ namespace OpenSim.Region.Framework.Scenes
4911 4997
4912 Changed changeFlags = 0; 4998 Changed changeFlags = 0;
4913 4999
5000 Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture;
5001 Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture;
5002
5003 // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all
5004 // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
5005 if (fallbackNewFace == null)
5006 {
5007 fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
5008 newTex.DefaultTexture = fallbackNewFace;
5009 }
5010 if (fallbackOldFace == null)
5011 {
5012 fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
5013 oldTex.DefaultTexture = fallbackOldFace;
5014 }
5015
4914 for (int i = 0 ; i < GetNumberOfSides(); i++) 5016 for (int i = 0 ; i < GetNumberOfSides(); i++)
4915 { 5017 {
5018
4916 Primitive.TextureEntryFace newFace = newTex.DefaultTexture; 5019 Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
4917 Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; 5020 Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
4918 5021
@@ -5138,9 +5241,12 @@ namespace OpenSim.Region.Framework.Scenes
5138 5241
5139 public void ApplyNextOwnerPermissions() 5242 public void ApplyNextOwnerPermissions()
5140 { 5243 {
5141 BaseMask &= NextOwnerMask; 5244 // Export needs to be preserved in the base and everyone
5245 // mask, but removed in the owner mask as a next owner
5246 // can never change the export status
5247 BaseMask &= NextOwnerMask | (uint)PermissionMask.Export;
5142 OwnerMask &= NextOwnerMask; 5248 OwnerMask &= NextOwnerMask;
5143 EveryoneMask &= NextOwnerMask; 5249 EveryoneMask &= NextOwnerMask | (uint)PermissionMask.Export;
5144 5250
5145 Inventory.ApplyNextOwnerPermissions(); 5251 Inventory.ApplyNextOwnerPermissions();
5146 } 5252 }
@@ -5202,18 +5308,22 @@ namespace OpenSim.Region.Framework.Scenes
5202 /// <param name='avatarId'></param> 5308 /// <param name='avatarId'></param>
5203 protected internal bool AddSittingAvatar(UUID avatarId) 5309 protected internal bool AddSittingAvatar(UUID avatarId)
5204 { 5310 {
5205 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) 5311 lock (ParentGroup.m_sittingAvatars)
5206 SitTargetAvatar = avatarId; 5312 {
5313 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
5314 SitTargetAvatar = avatarId;
5207 5315
5208 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5316 if (m_sittingAvatars == null)
5317 m_sittingAvatars = new HashSet<UUID>();
5209 5318
5210 if (sittingAvatars == null) 5319 if (m_sittingAvatars.Add(avatarId))
5211 sittingAvatars = new HashSet<UUID>(); 5320 {
5321 ParentGroup.m_sittingAvatars.Add(avatarId);
5212 5322
5213 lock (sittingAvatars) 5323 return true;
5214 { 5324 }
5215 m_sittingAvatars = sittingAvatars; 5325
5216 return m_sittingAvatars.Add(avatarId); 5326 return false;
5217 } 5327 }
5218 } 5328 }
5219 5329
@@ -5227,27 +5337,26 @@ namespace OpenSim.Region.Framework.Scenes
5227 /// <param name='avatarId'></param> 5337 /// <param name='avatarId'></param>
5228 protected internal bool RemoveSittingAvatar(UUID avatarId) 5338 protected internal bool RemoveSittingAvatar(UUID avatarId)
5229 { 5339 {
5230 if (SitTargetAvatar == avatarId) 5340 lock (ParentGroup.m_sittingAvatars)
5231 SitTargetAvatar = UUID.Zero; 5341 {
5232 5342 if (SitTargetAvatar == avatarId)
5233 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5343 SitTargetAvatar = UUID.Zero;
5234 5344
5235 // This can occur under a race condition where another thread 5345 if (m_sittingAvatars == null)
5236 if (sittingAvatars == null) 5346 return false;
5237 return false;
5238 5347
5239 lock (sittingAvatars) 5348 if (m_sittingAvatars.Remove(avatarId))
5240 {
5241 if (sittingAvatars.Remove(avatarId))
5242 { 5349 {
5243 if (sittingAvatars.Count == 0) 5350 if (m_sittingAvatars.Count == 0)
5244 m_sittingAvatars = null; 5351 m_sittingAvatars = null;
5245 5352
5353 ParentGroup.m_sittingAvatars.Remove(avatarId);
5354
5246 return true; 5355 return true;
5247 } 5356 }
5248 }
5249 5357
5250 return false; 5358 return false;
5359 }
5251 } 5360 }
5252 5361
5253 /// <summary> 5362 /// <summary>
@@ -5257,16 +5366,12 @@ namespace OpenSim.Region.Framework.Scenes
5257 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> 5366 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
5258 public HashSet<UUID> GetSittingAvatars() 5367 public HashSet<UUID> GetSittingAvatars()
5259 { 5368 {
5260 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5369 lock (ParentGroup.m_sittingAvatars)
5261
5262 if (sittingAvatars == null)
5263 {
5264 return null;
5265 }
5266 else
5267 { 5370 {
5268 lock (sittingAvatars) 5371 if (m_sittingAvatars == null)
5269 return new HashSet<UUID>(sittingAvatars); 5372 return null;
5373 else
5374 return new HashSet<UUID>(m_sittingAvatars);
5270 } 5375 }
5271 } 5376 }
5272 5377
@@ -5277,13 +5382,13 @@ namespace OpenSim.Region.Framework.Scenes
5277 /// <returns></returns> 5382 /// <returns></returns>
5278 public int GetSittingAvatarsCount() 5383 public int GetSittingAvatarsCount()
5279 { 5384 {
5280 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5385 lock (ParentGroup.m_sittingAvatars)
5281 5386 {
5282 if (sittingAvatars == null) 5387 if (m_sittingAvatars == null)
5283 return 0; 5388 return 0;
5284 5389 else
5285 lock (sittingAvatars) 5390 return m_sittingAvatars.Count;
5286 return sittingAvatars.Count; 5391 }
5287 } 5392 }
5288 } 5393 }
5289} 5394}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 3a9a146..d04d87b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -38,6 +38,7 @@ using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes.Scripting; 39using OpenSim.Region.Framework.Scenes.Scripting;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
43{ 44{
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index a9195f7..0ab267a 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -204,6 +204,11 @@ namespace OpenSim.Region.Framework.Scenes
204 204
205 private const int LAND_VELOCITYMAG_MAX = 12; 205 private const int LAND_VELOCITYMAG_MAX = 12;
206 206
207 private const float FLY_ROLL_MAX_RADIANS = 1.1f;
208
209 private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f;
210 private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f;
211
207 private float m_health = 100f; 212 private float m_health = 100f;
208 213
209 protected ulong crossingFromRegion; 214 protected ulong crossingFromRegion;
@@ -216,8 +221,6 @@ namespace OpenSim.Region.Framework.Scenes
216 221
217 private Quaternion m_headrotation = Quaternion.Identity; 222 private Quaternion m_headrotation = Quaternion.Identity;
218 223
219 private string m_nextSitAnimation = String.Empty;
220
221 //PauPaw:Proper PID Controler for autopilot************ 224 //PauPaw:Proper PID Controler for autopilot************
222 public bool MovingToTarget { get; private set; } 225 public bool MovingToTarget { get; private set; }
223 public Vector3 MoveToPositionTarget { get; private set; } 226 public Vector3 MoveToPositionTarget { get; private set; }
@@ -438,6 +441,8 @@ namespace OpenSim.Region.Framework.Scenes
438 get { return (IClientCore)ControllingClient; } 441 get { return (IClientCore)ControllingClient; }
439 } 442 }
440 443
444 public UUID COF { get; set; }
445
441// public Vector3 ParentPosition { get; set; } 446// public Vector3 ParentPosition { get; set; }
442 447
443 /// <summary> 448 /// <summary>
@@ -451,9 +456,9 @@ namespace OpenSim.Region.Framework.Scenes
451 { 456 {
452 m_pos = PhysicsActor.Position; 457 m_pos = PhysicsActor.Position;
453 458
454 //m_log.DebugFormat( 459// m_log.DebugFormat(
455 // "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!", 460// "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!",
456 // m_pos, Name, Scene.RegionInfo.RegionName); 461// Name, Scene.Name, m_pos);
457 } 462 }
458 else 463 else
459 { 464 {
@@ -480,6 +485,9 @@ namespace OpenSim.Region.Framework.Scenes
480 } 485 }
481 set 486 set
482 { 487 {
488// m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} in {1} to {2}", Name, Scene.Name, value);
489// Util.PrintCallStack();
490
483 if (PhysicsActor != null) 491 if (PhysicsActor != null)
484 { 492 {
485 try 493 try
@@ -585,27 +593,48 @@ namespace OpenSim.Region.Framework.Scenes
585*/ 593*/
586 private Quaternion m_bodyRot = Quaternion.Identity; 594 private Quaternion m_bodyRot = Quaternion.Identity;
587 595
596 /// <summary>
597 /// The rotation of the avatar.
598 /// </summary>
599 /// <remarks>
600 /// If the avatar is not sitting, this is with respect to the world
601 /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
602 /// If you always want the world rotation, use GetWorldRotation()
603 /// </remarks>
588 public Quaternion Rotation 604 public Quaternion Rotation
589 { 605 {
590 get { return m_bodyRot; } 606 get
607 {
608 return m_bodyRot;
609 }
610
591 set 611 set
592 { 612 {
593 m_bodyRot = value; 613 m_bodyRot = value;
594 // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); 614
595 if (PhysicsActor != null) 615 if (PhysicsActor != null)
596 { 616 {
597 try 617 try
598 { 618 {
599 PhysicsActor.Orientation = value; 619 PhysicsActor.Orientation = m_bodyRot;
600 } 620 }
601 catch (Exception e) 621 catch (Exception e)
602 { 622 {
603 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message); 623 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message);
604 } 624 }
605 } 625 }
626// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
606 } 627 }
607 } 628 }
608 629
630 // Used for limited viewer 'fake' user rotations.
631 private Vector3 m_AngularVelocity = Vector3.Zero;
632
633 public Vector3 AngularVelocity
634 {
635 get { return m_AngularVelocity; }
636 }
637
609 public bool IsChildAgent { get; set; } 638 public bool IsChildAgent { get; set; }
610 public bool IsLoggingIn { get; set; } 639 public bool IsLoggingIn { get; set; }
611 640
@@ -641,6 +670,26 @@ namespace OpenSim.Region.Framework.Scenes
641 set { m_health = value; } 670 set { m_health = value; }
642 } 671 }
643 672
673 /// <summary>
674 /// Gets the world rotation of this presence.
675 /// </summary>
676 /// <remarks>
677 /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not.
678 /// </remarks>
679 /// <returns></returns>
680 public Quaternion GetWorldRotation()
681 {
682 if (IsSatOnObject)
683 {
684 SceneObjectPart sitPart = ParentPart;
685
686 if (sitPart != null)
687 return sitPart.GetWorldRotation() * Rotation;
688 }
689
690 return Rotation;
691 }
692
644 public void AdjustKnownSeeds() 693 public void AdjustKnownSeeds()
645 { 694 {
646 Dictionary<ulong, string> seeds; 695 Dictionary<ulong, string> seeds;
@@ -690,6 +739,12 @@ namespace OpenSim.Region.Framework.Scenes
690 739
691 private bool m_inTransit; 740 private bool m_inTransit;
692 741
742 /// <summary>
743 /// This signals whether the presence is in transit between neighbouring regions.
744 /// </summary>
745 /// <remarks>
746 /// It is not set when the presence is teleporting or logging in/out directly to a region.
747 /// </remarks>
693 public bool IsInTransit 748 public bool IsInTransit
694 { 749 {
695 get { return m_inTransit; } 750 get { return m_inTransit; }
@@ -886,8 +941,6 @@ namespace OpenSim.Region.Framework.Scenes
886 "[SCENE]: Upgrading child to root agent for {0} in {1}", 941 "[SCENE]: Upgrading child to root agent for {0} in {1}",
887 Name, m_scene.RegionInfo.RegionName); 942 Name, m_scene.RegionInfo.RegionName);
888 943
889 bool wasChild = IsChildAgent;
890
891 if (ParentUUID != UUID.Zero) 944 if (ParentUUID != UUID.Zero)
892 { 945 {
893 m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); 946 m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
@@ -920,6 +973,9 @@ namespace OpenSim.Region.Framework.Scenes
920 IsLoggingIn = false; 973 IsLoggingIn = false;
921 } 974 }
922 975
976 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
977
978 IsChildAgent = false;
923 979
924 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 980 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
925 if (gm != null) 981 if (gm != null)
@@ -1013,6 +1069,13 @@ namespace OpenSim.Region.Framework.Scenes
1013 else 1069 else
1014 AddToPhysicalScene(isFlying); 1070 AddToPhysicalScene(isFlying);
1015 1071
1072 // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
1073 // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it
1074 // since it requires a physics actor to be present. If it is left any later, then physics appears to reset
1075 // the value to a negative position which does not trigger the border cross.
1076 // This may not be the best location for this.
1077 CheckForBorderCrossing();
1078
1016 if (ForceFly) 1079 if (ForceFly)
1017 { 1080 {
1018 Flying = true; 1081 Flying = true;
@@ -1033,22 +1096,43 @@ namespace OpenSim.Region.Framework.Scenes
1033 // and it has already rezzed the attachments and started their scripts. 1096 // and it has already rezzed the attachments and started their scripts.
1034 // We do the following only for non-login agents, because their scripts 1097 // We do the following only for non-login agents, because their scripts
1035 // haven't started yet. 1098 // haven't started yet.
1036 lock (m_attachments) 1099 if (PresenceType == PresenceType.Npc || (TeleportFlags & TeleportFlags.ViaLogin) != 0)
1037 { 1100 {
1038 if (wasChild && HasAttachments()) 1101 // Viewers which have a current outfit folder will actually rez their own attachments. However,
1102 // viewers without (e.g. v1 viewers) will not, so we still need to make this call.
1103 if (Scene.AttachmentsModule != null)
1104 Util.FireAndForget(
1105 o =>
1106 {
1107// if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None)
1108// System.Threading.Thread.Sleep(7000);
1109
1110 Scene.AttachmentsModule.RezAttachments(this);
1111 });
1112 }
1113 else
1114 {
1115 // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
1116 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
1117 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
1118 // not transporting the required data.
1119 lock (m_attachments)
1039 { 1120 {
1040 m_log.DebugFormat( 1121 if (HasAttachments())
1041 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); 1122 {
1042 1123 m_log.DebugFormat(
1043 // Resume scripts 1124 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
1044 Util.FireAndForget(delegate(object x) { 1125
1045 foreach (SceneObjectGroup sog in m_attachments) 1126 // Resume scripts
1046 { 1127 Util.FireAndForget(delegate(object x) {
1047 sog.ScheduleGroupForFullUpdate(); 1128 foreach (SceneObjectGroup sog in m_attachments)
1048 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); 1129 {
1049 sog.ResumeScripts(); 1130 sog.ScheduleGroupForFullUpdate();
1050 } 1131 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
1051 }); 1132 sog.ResumeScripts();
1133 }
1134 });
1135 }
1052 } 1136 }
1053 } 1137 }
1054 1138
@@ -1225,6 +1309,85 @@ namespace OpenSim.Region.Framework.Scenes
1225 ControllingClient.StopFlying(this); 1309 ControllingClient.StopFlying(this);
1226 } 1310 }
1227 1311
1312 /// <summary>
1313 /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect.
1314 /// </summary>
1315 /// <param name="amount">Postive or negative roll amount in radians</param>
1316 private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown)
1317 {
1318
1319 float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS);
1320 m_AngularVelocity.Z = rollAmount;
1321
1322 // APPLY EXTRA consideration for flying up and flying down during this time.
1323 // if we're turning left
1324 if (amount > 0)
1325 {
1326
1327 // If we're at the max roll and pressing up, we want to swing BACK a bit
1328 // Automatically adds noise
1329 if (PressingUp)
1330 {
1331 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f)
1332 m_AngularVelocity.Z -= 0.9f;
1333 }
1334 // If we're at the max roll and pressing down, we want to swing MORE a bit
1335 if (PressingDown)
1336 {
1337 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f)
1338 m_AngularVelocity.Z += 0.6f;
1339 }
1340 }
1341 else // we're turning right.
1342 {
1343 // If we're at the max roll and pressing up, we want to swing BACK a bit
1344 // Automatically adds noise
1345 if (PressingUp)
1346 {
1347 if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS))
1348 m_AngularVelocity.Z += 0.6f;
1349 }
1350 // If we're at the max roll and pressing down, we want to swing MORE a bit
1351 if (PressingDown)
1352 {
1353 if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f)
1354 m_AngularVelocity.Z -= 0.6f;
1355 }
1356 }
1357 }
1358
1359 /// <summary>
1360 /// incrementally sets roll amount to zero
1361 /// </summary>
1362 /// <param name="amount">Positive roll amount in radians</param>
1363 /// <returns></returns>
1364 private float CalculateFlyingRollResetToZero(float amount)
1365 {
1366 const float rollMinRadians = 0f;
1367
1368 if (m_AngularVelocity.Z > 0)
1369 {
1370
1371 float leftOverToMin = m_AngularVelocity.Z - rollMinRadians;
1372 if (amount > leftOverToMin)
1373 return -leftOverToMin;
1374 else
1375 return -amount;
1376
1377 }
1378 else
1379 {
1380
1381 float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians;
1382 if (amount > leftOverToMin)
1383 return leftOverToMin;
1384 else
1385 return amount;
1386 }
1387 }
1388
1389
1390
1228 // neighbouring regions we have enabled a child agent in 1391 // neighbouring regions we have enabled a child agent in
1229 // holds the seed cap for the child agent in that region 1392 // holds the seed cap for the child agent in that region
1230 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>(); 1393 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>();
@@ -1398,6 +1561,15 @@ namespace OpenSim.Region.Framework.Scenes
1398 1561
1399 } 1562 }
1400 1563
1564 // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region
1565 // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
1566 // This may be due to viewer code or it may be something we're not doing properly simulator side.
1567 lock (m_attachments)
1568 {
1569 foreach (SceneObjectGroup sog in m_attachments)
1570 sog.ScheduleGroupForFullUpdate();
1571 }
1572
1401// m_log.DebugFormat( 1573// m_log.DebugFormat(
1402// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", 1574// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
1403// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); 1575// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
@@ -1430,17 +1602,42 @@ namespace OpenSim.Region.Framework.Scenes
1430 m_doingCamRayCast = false; 1602 m_doingCamRayCast = false;
1431 if (hitYN && localid != LocalId) 1603 if (hitYN && localid != LocalId)
1432 { 1604 {
1433 CameraConstraintActive = true; 1605 SceneObjectGroup group = m_scene.GetGroupByPrim(localid);
1434 pNormal.X = (float)Math.Round(pNormal.X, 2); 1606 bool IsPrim = group != null;
1435 pNormal.Y = (float)Math.Round(pNormal.Y, 2); 1607 if (IsPrim)
1436 pNormal.Z = (float)Math.Round(pNormal.Z, 2); 1608 {
1437 pNormal.Normalize(); 1609 SceneObjectPart part = group.GetPart(localid);
1438 collisionPoint.X = (float)Math.Round(collisionPoint.X, 1); 1610 if (part != null && !part.VolumeDetectActive)
1439 collisionPoint.Y = (float)Math.Round(collisionPoint.Y, 1); 1611 {
1440 collisionPoint.Z = (float)Math.Round(collisionPoint.Z, 1); 1612 CameraConstraintActive = true;
1441 1613 pNormal.X = (float) Math.Round(pNormal.X, 2);
1442 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, Vector3.Dot(collisionPoint, pNormal)); 1614 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1443 UpdateCameraCollisionPlane(plane); 1615 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1616 pNormal.Normalize();
1617 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1618 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1619 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1620
1621 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1622 Vector3.Dot(collisionPoint, pNormal));
1623 UpdateCameraCollisionPlane(plane);
1624 }
1625 }
1626 else
1627 {
1628 CameraConstraintActive = true;
1629 pNormal.X = (float) Math.Round(pNormal.X, 2);
1630 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1631 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1632 pNormal.Normalize();
1633 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1634 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1635 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1636
1637 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1638 Vector3.Dot(collisionPoint, pNormal));
1639 UpdateCameraCollisionPlane(plane);
1640 }
1444 } 1641 }
1445 else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || 1642 else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
1446 !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) 1643 !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE))
@@ -1741,6 +1938,29 @@ namespace OpenSim.Region.Framework.Scenes
1741 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || 1938 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
1742 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 1939 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
1743 1940
1941 //m_log.Debug("[CONTROL]: " +flags);
1942 // Applies a satisfying roll effect to the avatar when flying.
1943 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
1944 {
1945 ApplyFlyingRoll(
1946 FLY_ROLL_RADIANS_PER_UPDATE,
1947 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
1948 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
1949 }
1950 else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
1951 (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
1952 {
1953 ApplyFlyingRoll(
1954 -FLY_ROLL_RADIANS_PER_UPDATE,
1955 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
1956 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
1957 }
1958 else
1959 {
1960 if (m_AngularVelocity.Z != 0)
1961 m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
1962 }
1963
1744 if (Flying && IsColliding && controlland) 1964 if (Flying && IsColliding && controlland)
1745 { 1965 {
1746 // nesting this check because LengthSquared() is expensive and we don't 1966 // nesting this check because LengthSquared() is expensive and we don't
@@ -1954,7 +2174,11 @@ namespace OpenSim.Region.Framework.Scenes
1954 // Get terrain height for sub-region in a megaregion if necessary 2174 // Get terrain height for sub-region in a megaregion if necessary
1955 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); 2175 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
1956 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); 2176 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
1957 UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID; 2177 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
2178 // If X and Y is NaN, target_region will be null
2179 if (target_region == null)
2180 return;
2181 UUID target_regionID = target_region.RegionID;
1958 Scene targetScene = m_scene; 2182 Scene targetScene = m_scene;
1959 2183
1960 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) 2184 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
@@ -2199,28 +2423,16 @@ namespace OpenSim.Region.Framework.Scenes
2199 2423
2200 if (ParentID != 0) 2424 if (ParentID != 0)
2201 { 2425 {
2426 if (ParentPart.UUID == targetID)
2427 return; // already sitting here, ignore
2428
2202 StandUp(); 2429 StandUp();
2203 } 2430 }
2204 2431
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); 2432 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2216 2433
2217 if (part != null) 2434 if (part != null)
2218 { 2435 {
2219 if (!String.IsNullOrEmpty(part.SitAnimation))
2220 {
2221 m_nextSitAnimation = part.SitAnimation;
2222 }
2223
2224 m_requestedSitTargetID = part.LocalId; 2436 m_requestedSitTargetID = part.LocalId;
2225 m_requestedSitTargetUUID = targetID; 2437 m_requestedSitTargetUUID = targetID;
2226 2438
@@ -2341,18 +2553,6 @@ namespace OpenSim.Region.Framework.Scenes
2341 2553
2342 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) 2554 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2343 { 2555 {
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); 2556 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2357 2557
2358 if (part != null) 2558 if (part != null)
@@ -2422,10 +2622,15 @@ namespace OpenSim.Region.Framework.Scenes
2422 2622
2423 ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 2623 ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2424 ParentID = m_requestedSitTargetID; 2624 ParentID = m_requestedSitTargetID;
2425 2625 m_AngularVelocity = Vector3.Zero;
2426 Velocity = Vector3.Zero; 2626 Velocity = Vector3.Zero;
2427 RemoveFromPhysicalScene(); 2627 RemoveFromPhysicalScene();
2428 2628
2629 String sitAnimation = "SIT";
2630 if (!String.IsNullOrEmpty(part.SitAnimation))
2631 {
2632 sitAnimation = part.SitAnimation;
2633 }
2429 Animator.TrySetMovementAnimation(sitAnimation); 2634 Animator.TrySetMovementAnimation(sitAnimation);
2430 SendAvatarDataToAllAgents(); 2635 SendAvatarDataToAllAgents();
2431 } 2636 }
@@ -2433,7 +2638,8 @@ namespace OpenSim.Region.Framework.Scenes
2433 2638
2434 public void HandleAgentSitOnGround() 2639 public void HandleAgentSitOnGround()
2435 { 2640 {
2436// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. 2641// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
2642 m_AngularVelocity = Vector3.Zero;
2437 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); 2643 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
2438 SitGround = true; 2644 SitGround = true;
2439 RemoveFromPhysicalScene(); 2645 RemoveFromPhysicalScene();
@@ -2455,7 +2661,7 @@ namespace OpenSim.Region.Framework.Scenes
2455 2661
2456 public void HandleStopAnim(IClientAPI remoteClient, UUID animID) 2662 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
2457 { 2663 {
2458 Animator.RemoveAnimation(animID); 2664 Animator.RemoveAnimation(animID, false);
2459 } 2665 }
2460 2666
2461 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) 2667 public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack)
@@ -2471,7 +2677,8 @@ namespace OpenSim.Region.Framework.Scenes
2471 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> 2677 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2472 public void AddNewMovement(Vector3 vec) 2678 public void AddNewMovement(Vector3 vec)
2473 { 2679 {
2474// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name); 2680// m_log.DebugFormat(
2681// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1} for {2}", vec, Rotation, Name);
2475 2682
2476 Vector3 direc = vec * Rotation; 2683 Vector3 direc = vec * Rotation;
2477 direc.Normalize(); 2684 direc.Normalize();
@@ -2491,6 +2698,8 @@ namespace OpenSim.Region.Framework.Scenes
2491 2698
2492 direc *= 0.03f * 128f * SpeedModifier; 2699 direc *= 0.03f * 128f * SpeedModifier;
2493 2700
2701// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
2702
2494 if (PhysicsActor != null) 2703 if (PhysicsActor != null)
2495 { 2704 {
2496 if (Flying) 2705 if (Flying)
@@ -2524,6 +2733,8 @@ namespace OpenSim.Region.Framework.Scenes
2524 } 2733 }
2525 } 2734 }
2526 2735
2736// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
2737
2527 // TODO: Add the force instead of only setting it to support multiple forces per frame? 2738 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2528 m_forceToApply = direc; 2739 m_forceToApply = direc;
2529 Animator.UpdateMovementAnimations(); 2740 Animator.UpdateMovementAnimations();
@@ -2942,6 +3153,10 @@ namespace OpenSim.Region.Framework.Scenes
2942 3153
2943 if (!IsInTransit) 3154 if (!IsInTransit)
2944 { 3155 {
3156// m_log.DebugFormat(
3157// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
3158// pos2, Name, Scene.Name);
3159
2945 // Checks if where it's headed exists a region 3160 // Checks if where it's headed exists a region
2946 bool needsTransit = false; 3161 bool needsTransit = false;
2947 if (m_scene.TestBorderCross(pos2, Cardinals.W)) 3162 if (m_scene.TestBorderCross(pos2, Cardinals.W))
@@ -4166,6 +4381,7 @@ namespace OpenSim.Region.Framework.Scenes
4166 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || 4381 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
4167 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) 4382 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
4168 { 4383 {
4384
4169 if (GodLevel < 200 && 4385 if (GodLevel < 200 &&
4170 ((!m_scene.Permissions.IsGod(m_uuid) && 4386 ((!m_scene.Permissions.IsGod(m_uuid) &&
4171 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || 4387 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
@@ -4174,7 +4390,14 @@ namespace OpenSim.Region.Framework.Scenes
4174 { 4390 {
4175 SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); 4391 SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
4176 if (spawnPoints.Length == 0) 4392 if (spawnPoints.Length == 0)
4393 {
4394 if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))
4395 {
4396 pos.X = 128.0f;
4397 pos.Y = 128.0f;
4398 }
4177 return; 4399 return;
4400 }
4178 4401
4179 int index; 4402 int index;
4180 bool selected = false; 4403 bool selected = false;
@@ -4183,6 +4406,8 @@ namespace OpenSim.Region.Framework.Scenes
4183 { 4406 {
4184 case "random": 4407 case "random":
4185 4408
4409 if (spawnPoints.Length == 0)
4410 return;
4186 do 4411 do
4187 { 4412 {
4188 index = Util.RandomClass.Next(spawnPoints.Length - 1); 4413 index = Util.RandomClass.Next(spawnPoints.Length - 1);
@@ -4194,6 +4419,7 @@ namespace OpenSim.Region.Framework.Scenes
4194 // SpawnPoint sp = spawnPoints[index]; 4419 // SpawnPoint sp = spawnPoints[index];
4195 4420
4196 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); 4421 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
4422
4197 if (land == null || land.IsEitherBannedOrRestricted(UUID)) 4423 if (land == null || land.IsEitherBannedOrRestricted(UUID))
4198 selected = false; 4424 selected = false;
4199 else 4425 else
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
deleted file mode 100644
index c58ccc5..0000000
--- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Original code: Tedd Hansen */
29using System;
30using System.IO;
31using System.Reflection;
32using log4net;
33
34namespace OpenSim.Region.Framework.Scenes.Scripting
35{
36 public class ScriptEngineLoader
37 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 public ScriptEngineInterface LoadScriptEngine(string EngineName)
41 {
42 ScriptEngineInterface ret = null;
43 try
44 {
45 ret =
46 LoadAndInitAssembly(
47 Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine." + EngineName + ".dll"),
48 "OpenSim.Region.ScriptEngine." + EngineName + ".ScriptEngine");
49 }
50 catch (Exception e)
51 {
52 m_log.Error("[ScriptEngine]: " +
53 "Error loading assembly \"" + EngineName + "\": " + e.Message + ", " +
54 e.StackTrace.ToString());
55 }
56 return ret;
57 }
58
59 /// <summary>
60 /// Does actual loading and initialization of script Assembly
61 /// </summary>
62 /// <param name="FreeAppDomain">AppDomain to load script into</param>
63 /// <param name="FileName">FileName of script assembly (.dll)</param>
64 /// <returns></returns>
65 private ScriptEngineInterface LoadAndInitAssembly(string FileName, string NameSpace)
66 {
67 //Common.SendToDebug("Loading ScriptEngine Assembly " + FileName);
68 // Load .Net Assembly (.dll)
69 // Initialize and return it
70
71 // TODO: Add error handling
72
73 Assembly a;
74 //try
75 //{
76
77
78 // Load to default appdomain (temporary)
79 a = Assembly.LoadFrom(FileName);
80 // Load to specified appdomain
81 // TODO: Insert security
82 //a = FreeAppDomain.Load(FileName);
83 //}
84 //catch (Exception e)
85 //{
86 // m_log.Error("[ScriptEngine]: Error loading assembly \String.Empty + FileName + "\": " + e.ToString());
87 //}
88
89
90 //m_log.Debug("Loading: " + FileName);
91 //foreach (Type _t in a.GetTypes())
92 //{
93 // m_log.Debug("Type: " + _t.ToString());
94 //}
95
96 Type t;
97 //try
98 //{
99 t = a.GetType(NameSpace, true);
100 //}
101 //catch (Exception e)
102 //{
103 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
104 //}
105
106 ScriptEngineInterface ret;
107 //try
108 //{
109 ret = (ScriptEngineInterface) Activator.CreateInstance(t);
110 //}
111 //catch (Exception e)
112 //{
113 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
114 //}
115
116 return ret;
117 }
118 }
119}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs
new file mode 100644
index 0000000..f08ba59
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs
@@ -0,0 +1,107 @@
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.Region.Framework.Scenes.Scripting
34{
35 /// <summary>
36 /// Utility functions for use by scripts manipulating the scene.
37 /// </summary>
38 public static class ScriptUtils
39 {
40 /// <summary>
41 /// Get an asset id given an item name and an item type.
42 /// </summary>
43 /// <returns>UUID.Zero if the name and type did not match any item.</returns>
44 /// <param name='part'></param>
45 /// <param name='name'></param>
46 /// <param name='type'></param>
47 public static UUID GetAssetIdFromItemName(SceneObjectPart part, string name, int type)
48 {
49 TaskInventoryItem item = part.Inventory.GetInventoryItem(name);
50
51 if (item != null && item.Type == type)
52 return item.AssetID;
53 else
54 return UUID.Zero;
55 }
56
57 /// <summary>
58 /// accepts a valid UUID, -or- a name of an inventory item.
59 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
60 /// in prim inventory.
61 /// </summary>
62 /// <param name="part">Scene object part to search for inventory item</param>
63 /// <param name="key"></param>
64 /// <returns></returns>
65 public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier)
66 {
67 UUID key;
68
69 // if we can parse the string as a key, use it.
70 // else try to locate the name in inventory of object. found returns key,
71 // not found returns UUID.Zero
72 if (!UUID.TryParse(identifier, out key))
73 {
74 TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier);
75
76 if (item != null)
77 key = item.AssetID;
78 else
79 key = UUID.Zero;
80 }
81
82 return key;
83 }
84
85 /// <summary>
86 /// Return the UUID of the asset matching the specified key or name
87 /// and asset type.
88 /// </summary>
89 /// <param name="part">Scene object part to search for inventory item</param>
90 /// <param name="identifier"></param>
91 /// <param name="type"></param>
92 /// <returns></returns>
93 public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier, AssetType type)
94 {
95 UUID key;
96
97 if (!UUID.TryParse(identifier, out key))
98 {
99 TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier);
100 if (item != null && item.Type == (int)type)
101 key = item.AssetID;
102 }
103
104 return key;
105 }
106 }
107} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
index a4f730d..5cb271d 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
@@ -42,9 +42,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
42 /// <summary> 42 /// <summary>
43 /// Serialize and deserialize coalesced scene objects. 43 /// Serialize and deserialize coalesced scene objects.
44 /// </summary> 44 /// </summary>
45 /// <remarks>
46 /// Deserialization not yet here.
47 /// </remarks>
48 public class CoalescedSceneObjectsSerializer 45 public class CoalescedSceneObjectsSerializer
49 { 46 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -128,6 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
128// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); 125// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
129 126
130 coa = null; 127 coa = null;
128 int i = 0;
131 129
132 using (StringReader sr = new StringReader(xml)) 130 using (StringReader sr = new StringReader(xml))
133 { 131 {
@@ -153,7 +151,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
153 if (reader.Name == "SceneObjectGroup") 151 if (reader.Name == "SceneObjectGroup")
154 { 152 {
155 string soXml = reader.ReadOuterXml(); 153 string soXml = reader.ReadOuterXml();
156 coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); 154
155 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);
156
157 if (so != null)
158 {
159 coa.Add(so);
160 }
161 else
162 {
163 // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
164 // coalesced object fails to load.
165 m_log.WarnFormat(
166 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
167 i);
168 }
169
170 i++;
157 } 171 }
158 } 172 }
159 173
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 123c158..ce4fb40 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -365,6 +365,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
365 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); 365 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound);
366 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); 366 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume);
367 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); 367 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl);
368 m_SOPXmlProcessors.Add("DynAttrs", ProcessDynAttrs);
368 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); 369 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation);
369 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); 370 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
370 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0); 371 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0);
@@ -633,7 +634,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
633 634
634 private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader) 635 private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader)
635 { 636 {
636 obj.Bounciness = reader.ReadElementContentAsFloat("Bounce", String.Empty); 637 obj.Restitution = reader.ReadElementContentAsFloat("Bounce", String.Empty);
637 } 638 }
638 639
639 private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader) 640 private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader)
@@ -797,6 +798,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
797 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); 798 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty);
798 } 799 }
799 800
801 private static void ProcessDynAttrs(SceneObjectPart obj, XmlTextReader reader)
802 {
803 obj.DynAttrs.ReadXml(reader);
804 }
805
800 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader) 806 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader)
801 { 807 {
802 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty)); 808 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty));
@@ -1339,6 +1345,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1339 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); 1345 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString());
1340 if (sop.MediaUrl != null) 1346 if (sop.MediaUrl != null)
1341 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); 1347 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString());
1348
1349 if (sop.DynAttrs.Count > 0)
1350 {
1351 writer.WriteStartElement("DynAttrs");
1352 sop.DynAttrs.WriteXml(writer);
1353 writer.WriteEndElement();
1354 }
1355
1342 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); 1356 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation);
1343 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); 1357 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
1344 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString()); 1358 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString());
@@ -1363,8 +1377,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1363 writer.WriteElementString("Density", sop.Density.ToString().ToLower()); 1377 writer.WriteElementString("Density", sop.Density.ToString().ToLower());
1364 if (sop.Friction != 0.6f) 1378 if (sop.Friction != 0.6f)
1365 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); 1379 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower());
1366 if (sop.Bounciness != 0.5f) 1380 if (sop.Restitution != 0.5f)
1367 writer.WriteElementString("Bounce", sop.Bounciness.ToString().ToLower()); 1381 writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower());
1368 if (sop.GravityModifier != 1.0f) 1382 if (sop.GravityModifier != 1.0f)
1369 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); 1383 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower());
1370 WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset()); 1384 WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset());
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..52ad538 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", false);
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/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index 5faf131..bbfbbfc 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -289,108 +289,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests
289// 289//
290// Assert.That(presence, Is.Null, "presence is not null"); 290// Assert.That(presence, Is.Null, "presence is not null");
291// } 291// }
292
293 // I'm commenting this test because it does not represent
294 // crossings. The Thread.Sleep's in here are not meaningful mocks,
295 // and they sometimes fail in panda.
296 // We need to talk in order to develop a test
297 // that really tests region crossings. There are 3 async components,
298 // but things are synchronous among them. So there should be
299 // 3 threads in here.
300 //[Test]
301// public void T021_TestCrossToNewRegion()
302// {
303// TestHelpers.InMethod();
304//
305// scene.RegisterRegionWithGrid();
306// scene2.RegisterRegionWithGrid();
307//
308// // Adding child agent to region 1001
309// string reason;
310// scene2.NewUserConnection(acd1,0, out reason);
311// scene2.AddNewClient(testclient, PresenceType.User);
312//
313// ScenePresence presence = scene.GetScenePresence(agent1);
314// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
315//
316// ScenePresence presence2 = scene2.GetScenePresence(agent1);
317//
318// // Adding neighbour region caps info to presence2
319//
320// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
321// presence2.AddNeighbourRegion(region1, cap);
322//
323// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
324// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
325//
326// // Cross to x+1
327// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
328// presence.Update();
329//
330// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
331//
332// // Mimicking communication between client and server, by waiting OK from client
333// // sent by TestClient.CrossRegion call. Originally, this is network comm.
334// if (!wh.WaitOne(5000,false))
335// {
336// presence.Update();
337// if (!wh.WaitOne(8000,false))
338// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
339// }
340//
341// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
342// // would normally be fired after receiving the reply packet from comm. done on the last line.
343// testclient.CompleteMovement();
344//
345// // Crossings are asynchronous
346// int timer = 10;
347//
348// // Make sure cross hasn't already finished
349// if (!presence.IsInTransit && !presence.IsChildAgent)
350// {
351// // If not and not in transit yet, give it some more time
352// Thread.Sleep(5000);
353// }
354//
355// // Enough time, should at least be in transit by now.
356// while (presence.IsInTransit && timer > 0)
357// {
358// Thread.Sleep(1000);
359// timer-=1;
360// }
361//
362// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
363// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
364// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
365//
366// // Cross Back
367// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
368// presence2.Update();
369//
370// if (!wh.WaitOne(5000,false))
371// {
372// presence2.Update();
373// if (!wh.WaitOne(8000,false))
374// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
375// }
376// testclient.CompleteMovement();
377//
378// if (!presence2.IsInTransit && !presence2.IsChildAgent)
379// {
380// // If not and not in transit yet, give it some more time
381// Thread.Sleep(5000);
382// }
383//
384// // Enough time, should at least be in transit by now.
385// while (presence2.IsInTransit && timer > 0)
386// {
387// Thread.Sleep(1000);
388// timer-=1;
389// }
390//
391// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
392// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
393// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
394// }
395 } 292 }
396} \ No newline at end of file 293} \ No newline at end of file
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/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
new file mode 100644
index 0000000..8775949
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
@@ -0,0 +1,162 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.CoreModules.Framework;
39using OpenSim.Region.CoreModules.Framework.EntityTransfer;
40using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43
44namespace OpenSim.Region.Framework.Scenes.Tests
45{
46 [TestFixture]
47 public class ScenePresenceCrossingTests : OpenSimTestCase
48 {
49 [TestFixtureSetUp]
50 public void FixtureInit()
51 {
52 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
53 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
54 }
55
56 [TestFixtureTearDown]
57 public void TearDown()
58 {
59 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
60 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
61 // tests really shouldn't).
62 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
63 }
64
65 [Test]
66 public void TestCrossOnSameSimulator()
67 {
68 TestHelpers.InMethod();
69// TestHelpers.EnableLogging();
70
71 UUID userId = TestHelpers.ParseTail(0x1);
72
73// TestEventQueueGetModule eqmA = new TestEventQueueGetModule();
74 EntityTransferModule etmA = new EntityTransferModule();
75 EntityTransferModule etmB = new EntityTransferModule();
76 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
77
78 IConfigSource config = new IniConfigSource();
79 IConfig modulesConfig = config.AddConfig("Modules");
80 modulesConfig.Set("EntityTransferModule", etmA.Name);
81 modulesConfig.Set("SimulationServices", lscm.Name);
82// IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
83
84 // In order to run a single threaded regression test we do not want the entity transfer module waiting
85 // for a callback from the destination scene before removing its avatar data.
86// entityTransferConfig.Set("wait_for_callback", false);
87
88 SceneHelpers sh = new SceneHelpers();
89 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
90 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
91
92 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
93 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
94// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA);
95 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
96
97 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
98 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
99 List<TestClient> destinationTestClients = new List<TestClient>();
100 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
101
102 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
103 originalSp.AbsolutePosition = new Vector3(128, 32, 10);
104
105// originalSp.Flying = true;
106
107// Console.WriteLine("First pos {0}", originalSp.AbsolutePosition);
108
109// eqmA.ClearEvents();
110
111 AgentUpdateArgs moveArgs = new AgentUpdateArgs();
112 //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero);
113 moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2)));
114 moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
115
116 originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs);
117
118 sceneA.Update(1);
119
120// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition);
121
122 // FIXME: This is a sufficient number of updates to for the presence to reach the northern border.
123 // But really we want to do this in a more robust way.
124 for (int i = 0; i < 100; i++)
125 {
126 sceneA.Update(1);
127// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition);
128 }
129
130 // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm
131 // messages
132// Dictionary<UUID, List<TestEventQueueGetModule.Event>> eqmEvents = eqmA.Events;
133//
134// Assert.That(eqmEvents.Count, Is.EqualTo(1));
135// Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True);
136//
137// List<TestEventQueueGetModule.Event> spEqmEvents = eqmEvents[originalSp.UUID];
138//
139// Assert.That(spEqmEvents.Count, Is.EqualTo(1));
140// Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion"));
141
142 // sceneA should now only have a child agent
143 ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID);
144 Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True);
145
146 ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID);
147
148 // Agent remains a child until the client triggers complete movement
149 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
150
151 TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient);
152
153 int agentMovementCompleteReceived = 0;
154 sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++;
155
156 sceneBTc.CompleteMovement();
157
158 Assert.That(agentMovementCompleteReceived, Is.EqualTo(1));
159 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False);
160 }
161 }
162} \ No newline at end of file
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..de4458d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -26,7 +26,10 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Text;
30using Nini.Config; 33using Nini.Config;
31using NUnit.Framework; 34using NUnit.Framework;
32using OpenMetaverse; 35using OpenMetaverse;
@@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
40using OpenSim.Region.CoreModules.World.Permissions; 43using OpenSim.Region.CoreModules.World.Permissions;
41using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock; 45using OpenSim.Tests.Common.Mock;
43using System.IO;
44using System.Text;
45 46
46namespace OpenSim.Region.Framework.Scenes.Tests 47namespace OpenSim.Region.Framework.Scenes.Tests
47{ 48{
@@ -49,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
49 /// Teleport tests in a standalone OpenSim 50 /// Teleport tests in a standalone OpenSim
50 /// </summary> 51 /// </summary>
51 [TestFixture] 52 [TestFixture]
52 public class ScenePresenceTeleportTests 53 public class ScenePresenceTeleportTests : OpenSimTestCase
53 { 54 {
54 [TestFixtureSetUp] 55 [TestFixtureSetUp]
55 public void FixtureInit() 56 public void FixtureInit()
@@ -68,7 +69,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
68 } 69 }
69 70
70 [Test] 71 [Test]
71 public void TestSameRegionTeleport() 72 public void TestSameRegion()
72 { 73 {
73 TestHelpers.InMethod(); 74 TestHelpers.InMethod();
74// log4net.Config.XmlConfigurator.Configure(); 75// log4net.Config.XmlConfigurator.Configure();
@@ -106,10 +107,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
106 } 107 }
107 108
108 [Test] 109 [Test]
109 public void TestSameSimulatorSeparatedRegionsTeleport() 110 public void TestSameSimulatorIsolatedRegions()
110 { 111 {
111 TestHelpers.InMethod(); 112 TestHelpers.InMethod();
112// log4net.Config.XmlConfigurator.Configure(); 113// TestHelpers.EnableLogging();
113 114
114 UUID userId = TestHelpers.ParseTail(0x1); 115 UUID userId = TestHelpers.ParseTail(0x1);
115 116
@@ -141,9 +142,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
141 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 142 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
142 sp.AbsolutePosition = new Vector3(30, 31, 32); 143 sp.AbsolutePosition = new Vector3(30, 31, 32);
143 144
144 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 145 List<TestClient> destinationTestClients = new List<TestClient>();
145 // UDP stack (?) 146 EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients);
146// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB;
147 147
148 sceneA.RequestTeleportLocation( 148 sceneA.RequestTeleportLocation(
149 sp.ControllingClient, 149 sp.ControllingClient,
@@ -152,7 +152,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
152 teleportLookAt, 152 teleportLookAt,
153 (uint)TeleportFlags.ViaLocation); 153 (uint)TeleportFlags.ViaLocation);
154 154
155 ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); 155 // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child
156 // agent. This call will now complete the movement of the user into the destination and upgrade the agent
157 // from child to root.
158 destinationTestClients[0].CompleteMovement();
156 159
157 Assert.That(sceneA.GetScenePresence(userId), Is.Null); 160 Assert.That(sceneA.GetScenePresence(userId), Is.Null);
158 161
@@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
177 /// Test teleport procedures when the target simulator returns false when queried about access. 180 /// Test teleport procedures when the target simulator returns false when queried about access.
178 /// </summary> 181 /// </summary>
179 [Test] 182 [Test]
180 public void TestSameSimulatorSeparatedRegionsQueryAccessFails() 183 public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess()
181 { 184 {
182 TestHelpers.InMethod(); 185 TestHelpers.InMethod();
183// TestHelpers.EnableLogging(); 186// TestHelpers.EnableLogging();
@@ -261,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
261 /// Test teleport procedures when the target simulator create agent step is refused. 264 /// Test teleport procedures when the target simulator create agent step is refused.
262 /// </summary> 265 /// </summary>
263 [Test] 266 [Test]
264 public void TestSameSimulatorSeparatedRegionsCreateAgentFails() 267 public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent()
265 { 268 {
266 TestHelpers.InMethod(); 269 TestHelpers.InMethod();
267// TestHelpers.EnableLogging(); 270// TestHelpers.EnableLogging();
@@ -333,13 +336,101 @@ namespace OpenSim.Region.Framework.Scenes.Tests
333// TestHelpers.DisableLogging(); 336// TestHelpers.DisableLogging();
334 } 337 }
335 338
339 /// <summary>
340 /// Test teleport when the destination region does not process (or does not receive) the connection attempt
341 /// from the viewer.
342 /// </summary>
343 /// <remarks>
344 /// This could be quite a common case where the source region can connect to a remove destination region
345 /// (for CreateAgent) but the viewer cannot reach the destination region due to network issues.
346 /// </remarks>
336 [Test] 347 [Test]
337 public void TestSameSimulatorNeighbouringRegionsTeleport() 348 public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection()
338 { 349 {
339 TestHelpers.InMethod(); 350 TestHelpers.InMethod();
340// TestHelpers.EnableLogging(); 351// TestHelpers.EnableLogging();
341 352
342 UUID userId = TestHelpers.ParseTail(0x1); 353 UUID userId = TestHelpers.ParseTail(0x1);
354 Vector3 preTeleportPosition = new Vector3(30, 31, 32);
355
356 EntityTransferModule etmA = new EntityTransferModule();
357 EntityTransferModule etmB = new EntityTransferModule();
358
359 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
360
361 IConfigSource config = new IniConfigSource();
362 config.AddConfig("Modules");
363 config.Configs["Modules"].Set("EntityTransferModule", etmA.Name);
364 config.Configs["Modules"].Set("SimulationServices", lscm.Name);
365
366 config.AddConfig("EntityTransfer");
367
368 // In order to run a single threaded regression test we do not want the entity transfer module waiting
369 // for a callback from the destination scene before removing its avatar data.
370 config.Configs["EntityTransfer"].Set("wait_for_callback", false);
371
372// config.AddConfig("Startup");
373// config.Configs["Startup"].Set("serverside_object_permissions", true);
374
375 SceneHelpers sh = new SceneHelpers();
376 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
377 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000);
378
379 SceneHelpers.SetupSceneModules(sceneA, config, etmA );
380
381 // We need to set up the permisions module on scene B so that our later use of agent limit to deny
382 // QueryAccess won't succeed anyway because administrators are always allowed in and the default
383 // IsAdministrator if no permissions module is present is true.
384 SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB });
385
386 // Shared scene modules
387 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
388
389 Vector3 teleportPosition = new Vector3(10, 11, 12);
390 Vector3 teleportLookAt = new Vector3(20, 21, 22);
391
392 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
393 sp.AbsolutePosition = preTeleportPosition;
394
395 sceneA.RequestTeleportLocation(
396 sp.ControllingClient,
397 sceneB.RegionInfo.RegionHandle,
398 teleportPosition,
399 teleportLookAt,
400 (uint)TeleportFlags.ViaLocation);
401
402 // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate
403 // communication with the destination region. But this is a very non-obvious way of doing it - really we
404 // should be forced to expicitly set this up.
405
406 Assert.That(sceneB.GetScenePresence(userId), Is.Null);
407
408 ScenePresence sceneASp = sceneA.GetScenePresence(userId);
409 Assert.That(sceneASp, Is.Not.Null);
410 Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName));
411 Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition));
412
413 Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1));
414 Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0));
415 Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0));
416 Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
417
418 // TODO: Add assertions to check correct circuit details in both scenes.
419
420 // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
421 // position instead).
422// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
423
424// TestHelpers.DisableLogging();
425 }
426
427 [Test]
428 public void TestSameSimulatorNeighbouringRegions()
429 {
430 TestHelpers.InMethod();
431 TestHelpers.EnableLogging();
432
433 UUID userId = TestHelpers.ParseTail(0x1);
343 434
344 EntityTransferModule etmA = new EntityTransferModule(); 435 EntityTransferModule etmA = new EntityTransferModule();
345 EntityTransferModule etmB = new EntityTransferModule(); 436 EntityTransferModule etmB = new EntityTransferModule();
@@ -366,10 +457,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests
366 Vector3 teleportPosition = new Vector3(10, 11, 12); 457 Vector3 teleportPosition = new Vector3(10, 11, 12);
367 Vector3 teleportLookAt = new Vector3(20, 21, 22); 458 Vector3 teleportLookAt = new Vector3(20, 21, 22);
368 459
369 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 460 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
370 originalSp.AbsolutePosition = new Vector3(30, 31, 32); 461 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
462 List<TestClient> destinationTestClients = new List<TestClient>();
463 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
464
465 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
466 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
371 467
372 ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId);
373 Assert.That(beforeSceneASp, Is.Not.Null); 468 Assert.That(beforeSceneASp, Is.Not.Null);
374 Assert.That(beforeSceneASp.IsChildAgent, Is.False); 469 Assert.That(beforeSceneASp.IsChildAgent, Is.False);
375 470
@@ -377,10 +472,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
377 Assert.That(beforeSceneBSp, Is.Not.Null); 472 Assert.That(beforeSceneBSp, Is.Not.Null);
378 Assert.That(beforeSceneBSp.IsChildAgent, Is.True); 473 Assert.That(beforeSceneBSp.IsChildAgent, Is.True);
379 474
380 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 475 // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows
381 // UDP stack (?) 476 // about the neighbour region it is teleporting to.
382// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB;
383
384 sceneA.RequestTeleportLocation( 477 sceneA.RequestTeleportLocation(
385 beforeSceneASp.ControllingClient, 478 beforeSceneASp.ControllingClient,
386 sceneB.RegionInfo.RegionHandle, 479 sceneB.RegionInfo.RegionHandle,
@@ -388,7 +481,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
388 teleportLookAt, 481 teleportLookAt,
389 (uint)TeleportFlags.ViaLocation); 482 (uint)TeleportFlags.ViaLocation);
390 483
391 ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); 484 destinationTestClients[0].CompleteMovement();
392 485
393 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); 486 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
394 Assert.That(afterSceneASp, Is.Not.Null); 487 Assert.That(afterSceneASp, Is.Not.Null);
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..6e0ea7d 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()
@@ -130,10 +130,10 @@ namespace OpenSim.Region.Framework.Tests
130 SceneObjectPart sop1 = sog1.RootPart; 130 SceneObjectPart sop1 = sog1.RootPart;
131 TaskInventoryItem sopItem1 131 TaskInventoryItem sopItem1
132 = TaskInventoryHelpers.AddNotecard( 132 = TaskInventoryHelpers.AddNotecard(
133 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 133 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
134 134
135 InventoryFolderBase folder 135 InventoryFolderBase folder
136 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; 136 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0];
137 137
138 // Perform test 138 // Perform test
139 scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID); 139 scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID);
@@ -162,7 +162,7 @@ namespace OpenSim.Region.Framework.Tests
162 SceneObjectPart sop1 = sog1.RootPart; 162 SceneObjectPart sop1 = sog1.RootPart;
163 TaskInventoryItem sopItem1 163 TaskInventoryItem sopItem1
164 = TaskInventoryHelpers.AddNotecard( 164 = TaskInventoryHelpers.AddNotecard(
165 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 165 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
166 166
167 // Perform test 167 // Perform test
168 scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID); 168 scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
index 9457ebb..e50b4da 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
@@ -64,7 +64,7 @@ namespace OpenSim.Region.Framework.Tests
64 Scene scene = new SceneHelpers().SetupScene(); 64 Scene scene = new SceneHelpers().SetupScene();
65 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); 65 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
66 66
67 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); 67 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false);
68 68
69 List<InventoryFolderBase> oneFolder 69 List<InventoryFolderBase> oneFolder
70 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); 70 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
@@ -73,7 +73,7 @@ namespace OpenSim.Region.Framework.Tests
73 InventoryFolderBase firstRetrievedFolder = oneFolder[0]; 73 InventoryFolderBase firstRetrievedFolder = oneFolder[0];
74 Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); 74 Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName));
75 75
76 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); 76 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false);
77 77
78 List<InventoryFolderBase> twoFolders 78 List<InventoryFolderBase> twoFolders
79 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); 79 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
@@ -121,7 +121,7 @@ namespace OpenSim.Region.Framework.Tests
121 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); 121 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
122 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); 122 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002));
123 InventoryFolderBase folder1 123 InventoryFolderBase folder1
124 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1"); 124 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1", false);
125 125
126 scene.GiveInventoryFolder(user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero); 126 scene.GiveInventoryFolder(user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero);
127 127
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/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index 2279e62..b09ae39 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -127,7 +127,10 @@ namespace OpenSim.Region.Framework.Scenes
127 /// within this object). 127 /// within this object).
128 /// </remarks> 128 /// </remarks>
129 /// <param name="sceneObject">The scene object for which to gather assets</param> 129 /// <param name="sceneObject">The scene object for which to gather assets</param>
130 /// <param name="assetUuids">The assets gathered</param> 130 /// <param name="assetUuids">
131 /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset.
132 /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown.
133 /// </param>
131 public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids) 134 public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids)
132 { 135 {
133// m_log.DebugFormat( 136// m_log.DebugFormat(
@@ -257,8 +260,9 @@ namespace OpenSim.Region.Framework.Scenes
257 UUID uuid = new UUID(uuidMatch.Value); 260 UUID uuid = new UUID(uuidMatch.Value);
258// m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); 261// m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
259 262
260 // Assume AssetIDs embedded are textures. 263 // Embedded asset references (if not false positives) could be for many types of asset, so we will
261 assetUuids[uuid] = AssetType.Texture; 264 // label these as unknown.
265 assetUuids[uuid] = AssetType.Unknown;
262 } 266 }
263 } 267 }
264 } 268 }
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 5ac4e27..686c605 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -976,12 +976,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
976 // TODO 976 // TODO
977 } 977 }
978 978
979 public void SendGenericMessage(string method, List<string> message) 979 public void SendGenericMessage(string method, UUID invoice, List<string> message)
980 { 980 {
981 981
982 } 982 }
983 983
984 public void SendGenericMessage(string method, List<byte[]> message) 984 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
985 { 985 {
986 986
987 } 987 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs
new file mode 100644
index 0000000..84211a9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.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 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, sp.Animator.GetAnimName(defaultAnimId)));
165
166 UUID implicitDefaultAnimId = anims.ImplicitDefaultAnimation.AnimID;
167 cdl.AddRow(
168 "Implicit default anim",
169 string.Format("{0}, {1}",
170 implicitDefaultAnimId, sp.Animator.GetAnimName(implicitDefaultAnimId)));
171
172 cdl.AddToStringBuilder(sb);
173
174 ConsoleDisplayTable cdt = new ConsoleDisplayTable() { Indent = 2 };
175 cdt.AddColumn("Animation ID", 36);
176 cdt.AddColumn("Name", 20);
177 cdt.AddColumn("Seq", 3);
178 cdt.AddColumn("Object ID", 36);
179
180 UUID[] animIds;
181 int[] sequenceNumbers;
182 UUID[] objectIds;
183
184 sp.Animator.Animations.GetArrays(out animIds, out sequenceNumbers, out objectIds);
185
186 for (int i = 0; i < animIds.Length; i++)
187 {
188 UUID animId = animIds[i];
189 string animName = sp.Animator.GetAnimName(animId);
190 int seq = sequenceNumbers[i];
191 UUID objectId = objectIds[i];
192
193 cdt.AddRow(animId, animName, seq, objectId);
194 }
195
196 cdt.AddToStringBuilder(sb);
197 sb.Append("\n");
198 }
199 }
200} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index d718a2f..fa35f0f 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -222,7 +222,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
222 { 222 {
223 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); 223 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp);
224 MainConsole.Instance.OutputFormat( 224 MainConsole.Instance.OutputFormat(
225 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 225 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
226 } 226 }
227 ); 227 );
228 } 228 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index 68bcb4a..0333747 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
@@ -175,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
175// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", 176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
176// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, 177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
177// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); 178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
178 ct.Rows.Add( 179
179 new ConsoleDisplayTableRow( 180 ct.AddRow(
180 new List<string>() 181 attachmentObject.Name,
181 { 182 attachmentObject.LocalId,
182 attachmentObject.Name, 183 attachmentObject.FromItemID,
183 attachmentObject.LocalId.ToString(), 184 ((AttachmentPoint)attachmentObject.AttachmentPoint),
184 attachmentObject.FromItemID.ToString(), 185 attachmentObject.RootPart.AttachedPos);
185 ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
186 attachmentObject.RootPart.AttachedPos.ToString()
187 }));
188// } 186// }
189 } 187 }
190 188
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
index 17971e3..d56e39d 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Framework.Monitoring;
40using OpenSim.Region.ClientStack.LindenUDP; 40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.OptionalModules.Avatar.Attachments 45namespace OpenSim.Region.OptionalModules.Avatar.Attachments
45{ 46{
@@ -76,7 +77,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
76 77
77 if (m_console != null) 78 if (m_console != null)
78 { 79 {
79 m_console.AddCommand("TempAttachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner os estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms); 80 m_console.AddCommand("TempAttachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner or estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms);
80 } 81 }
81 } 82 }
82 else 83 else
@@ -183,7 +184,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
183 hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); 184 hostPart.ParentGroup.RootPart.ScheduleFullUpdate();
184 } 185 }
185 186
186 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true) ? 1 : 0; 187 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true, true) ? 1 : 0;
187 } 188 }
188 } 189 }
189} 190}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
index 66265d8..5a37fad 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
@@ -55,42 +55,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
55 // These are the IRC Connector configurable parameters with hard-wired 55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability). 56 // default values (retained for compatability).
57 57
58 internal string Server = null; 58 internal string Server = null;
59 internal string Password = null; 59 internal string Password = null;
60 internal string IrcChannel = null; 60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot"; 61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667; 62 internal uint Port = 6667;
63 internal string User = null; 63 internal string User = null;
64 64
65 internal bool ClientReporting = true; 65 internal bool ClientReporting = true;
66 internal bool RelayChat = true; 66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false; 67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1; 68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>(); 69 internal List<int> ValidInWorldChannels = new List<int>();
70 70
71 // Connector agnostic parameters. These values are NOT shared with the 71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level 72 // connector and do not differentiate at an IRC level
73 73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}"; 74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; 75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1; 76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true; 77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false; 78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1; 79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10; 80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15; 81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim"; 82 internal string DefaultZone = "Sim";
83 83
84 internal string _accessPassword = String.Empty; 84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null; 85 internal Regex AccessPasswordRegex = null;
86 internal List<string> ExcludeList = new List<string>(); 86 internal List<string> ExcludeList = new List<string>();
87 internal string AccessPassword 87 internal string AccessPassword
88 { 88 {
89 get { return _accessPassword; } 89 get { return _accessPassword; }
90 set 90 set
91 { 91 {
92 _accessPassword = value; 92 _accessPassword = value;
93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword), 93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
94 RegexOptions.Compiled); 94 RegexOptions.Compiled);
95 } 95 }
96 } 96 }
@@ -99,9 +99,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
99 99
100 // IRC connector reference 100 // IRC connector reference
101 101
102 internal IRCConnector irc = null; 102 internal IRCConnector irc = null;
103 103
104 internal int idn = _idk_++; 104 internal int idn = _idk_++;
105 105
106 // List of regions dependent upon this connection 106 // List of regions dependent upon this connection
107 107
@@ -119,29 +119,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
119 119
120 internal ChannelState(ChannelState model) 120 internal ChannelState(ChannelState model)
121 { 121 {
122 Server = model.Server; 122 Server = model.Server;
123 Password = model.Password; 123 Password = model.Password;
124 IrcChannel = model.IrcChannel; 124 IrcChannel = model.IrcChannel;
125 Port = model.Port; 125 Port = model.Port;
126 BaseNickname = model.BaseNickname; 126 BaseNickname = model.BaseNickname;
127 RandomizeNickname = model.RandomizeNickname; 127 RandomizeNickname = model.RandomizeNickname;
128 User = model.User; 128 User = model.User;
129 CommandsEnabled = model.CommandsEnabled; 129 CommandsEnabled = model.CommandsEnabled;
130 CommandChannel = model.CommandChannel; 130 CommandChannel = model.CommandChannel;
131 RelayChat = model.RelayChat; 131 RelayChat = model.RelayChat;
132 RelayPrivateChannels = model.RelayPrivateChannels; 132 RelayPrivateChannels = model.RelayPrivateChannels;
133 RelayChannelOut = model.RelayChannelOut; 133 RelayChannelOut = model.RelayChannelOut;
134 RelayChannel = model.RelayChannel; 134 RelayChannel = model.RelayChannel;
135 ValidInWorldChannels = model.ValidInWorldChannels; 135 ValidInWorldChannels = model.ValidInWorldChannels;
136 PrivateMessageFormat = model.PrivateMessageFormat; 136 PrivateMessageFormat = model.PrivateMessageFormat;
137 NoticeMessageFormat = model.NoticeMessageFormat; 137 NoticeMessageFormat = model.NoticeMessageFormat;
138 ClientReporting = model.ClientReporting; 138 ClientReporting = model.ClientReporting;
139 AccessPassword = model.AccessPassword; 139 AccessPassword = model.AccessPassword;
140 DefaultZone = model.DefaultZone; 140 DefaultZone = model.DefaultZone;
141 ConnectDelay = model.ConnectDelay; 141 ConnectDelay = model.ConnectDelay;
142 PingDelay = model.PingDelay; 142 PingDelay = model.PingDelay;
143 } 143 }
144 144
145 // Read the configuration file, performing variable substitution and any 145 // Read the configuration file, performing variable substitution and any
146 // necessary aliasing. See accompanying documentation for how this works. 146 // necessary aliasing. See accompanying documentation for how this works.
147 // If you don't need variables, then this works exactly as before. 147 // If you don't need variables, then this works exactly as before.
@@ -160,54 +160,54 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
160 160
161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region); 161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
162 162
163 cs.Server = Substitute(rs, config.GetString("server", null)); 163 cs.Server = Substitute(rs, config.GetString("server", null));
164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server); 164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
165 cs.Password = Substitute(rs, config.GetString("password", null)); 165 cs.Password = Substitute(rs, config.GetString("password", null));
166 // probably not a good idea to put a password in the log file 166 // probably not a good idea to put a password in the log file
167 cs.User = Substitute(rs, config.GetString("user", null)); 167 cs.User = Substitute(rs, config.GetString("user", null));
168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); 168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel); 169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); 170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port); 171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); 172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname); 173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); 174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); 176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
178 cs.User = Substitute(rs, config.GetString("username", cs.User)); 178 cs.User = Substitute(rs, config.GetString("username", cs.User));
179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User); 179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); 180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled); 181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); 182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); 184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); 186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat); 187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels)))); 188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels)))); 190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); 192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut); 193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); 194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); 196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat)); 198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat); 199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat)); 200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat); 201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0; 202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0;
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); 204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); 206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone); 207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); 208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay); 209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); 210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay); 211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword)); 212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword); 213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
@@ -217,7 +217,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
217 { 217 {
218 cs.ExcludeList.Add(name.Trim().ToLower()); 218 cs.ExcludeList.Add(name.Trim().ToLower());
219 } 219 }
220 220
221 // Fail if fundamental information is still missing 221 // Fail if fundamental information is still missing
222 222
223 if (cs.Server == null) 223 if (cs.Server == null)
@@ -306,8 +306,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
306 306
307 IRCBridgeModule.m_channels.Add(cs); 307 IRCBridgeModule.m_channels.Add(cs);
308 308
309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", 309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
310 cs.idn, rs.Region, cs.DefaultZone, 310 cs.idn, rs.Region, cs.DefaultZone,
311 cs.CommandsEnabled ? "enabled" : "not enabled", 311 cs.CommandsEnabled ? "enabled" : "not enabled",
312 cs.RelayPrivateChannels ? "relayed" : "not relayed"); 312 cs.RelayPrivateChannels ? "relayed" : "not relayed");
313 } 313 }
@@ -417,7 +417,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
417 private bool IsAConnectionMatchFor(ChannelState cs) 417 private bool IsAConnectionMatchFor(ChannelState cs)
418 { 418 {
419 return ( 419 return (
420 Server == cs.Server && 420 Server == cs.Server &&
421 IrcChannel == cs.IrcChannel && 421 IrcChannel == cs.IrcChannel &&
422 Port == cs.Port && 422 Port == cs.Port &&
423 BaseNickname == cs.BaseNickname && 423 BaseNickname == cs.BaseNickname &&
@@ -473,27 +473,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
473 { 473 {
474 474
475 string vvar = arg.Match(result).ToString(); 475 string vvar = arg.Match(result).ToString();
476 string var = vvar.Substring(1,vvar.Length-2).Trim(); 476 string var = vvar.Substring(1, vvar.Length - 2).Trim();
477 477
478 switch (var.ToLower()) 478 switch (var.ToLower())
479 { 479 {
480 case "%region" : 480 case "%region":
481 result = result.Replace(vvar, rs.Region); 481 result = result.Replace(vvar, rs.Region);
482 break; 482 break;
483 case "%host" : 483 case "%host":
484 result = result.Replace(vvar, rs.Host); 484 result = result.Replace(vvar, rs.Host);
485 break; 485 break;
486 case "%locx" : 486 case "%locx":
487 result = result.Replace(vvar, rs.LocX); 487 result = result.Replace(vvar, rs.LocX);
488 break; 488 break;
489 case "%locy" : 489 case "%locy":
490 result = result.Replace(vvar, rs.LocY); 490 result = result.Replace(vvar, rs.LocY);
491 break; 491 break;
492 case "%k" : 492 case "%k":
493 result = result.Replace(vvar, rs.IDK); 493 result = result.Replace(vvar, rs.IDK);
494 break; 494 break;
495 default : 495 default:
496 result = result.Replace(vvar, rs.config.GetString(var,var)); 496 result = result.Replace(vvar, rs.config.GetString(var, var));
497 break; 497 break;
498 } 498 }
499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result); 499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
index 2e1d03d..351dbfe 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
@@ -46,18 +46,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 internal static bool m_pluginEnabled = false; 49 internal static bool Enabled = false;
50 internal static IConfig m_config = null; 50 internal static IConfig m_config = null;
51 51
52 internal static List<ChannelState> m_channels = new List<ChannelState>(); 52 internal static List<ChannelState> m_channels = new List<ChannelState>();
53 internal static List<RegionState> m_regions = new List<RegionState>(); 53 internal static List<RegionState> m_regions = new List<RegionState>();
54 54
55 internal static string m_password = String.Empty; 55 internal static string m_password = String.Empty;
56 internal RegionState m_region = null; 56 internal RegionState m_region = null;
57 57
58 #region INonSharedRegionModule Members 58 #region INonSharedRegionModule Members
59 59
60 public Type ReplaceableInterface 60 public Type ReplaceableInterface
61 { 61 {
62 get { return null; } 62 get { return null; }
63 } 63 }
@@ -72,13 +72,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
72 m_config = config.Configs["IRC"]; 72 m_config = config.Configs["IRC"];
73 if (m_config == null) 73 if (m_config == null)
74 { 74 {
75// m_log.InfoFormat("[IRC-Bridge] module not configured"); 75 // m_log.InfoFormat("[IRC-Bridge] module not configured");
76 return; 76 return;
77 } 77 }
78 78
79 if (!m_config.GetBoolean("enabled", false)) 79 if (!m_config.GetBoolean("enabled", false))
80 { 80 {
81// m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); 81 // m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
82 return; 82 return;
83 } 83 }
84 84
@@ -87,19 +87,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password); 87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password);
88 } 88 }
89 89
90 m_pluginEnabled = true; 90 Enabled = true;
91 m_log.InfoFormat("[IRC-Bridge]: Module enabled"); 91
92 m_log.InfoFormat("[IRC-Bridge]: Module is enabled");
92 } 93 }
93 94
94 public void AddRegion(Scene scene) 95 public void AddRegion(Scene scene)
95 { 96 {
96 if (m_pluginEnabled) 97 if (Enabled)
97 { 98 {
98 try 99 try
99 { 100 {
100 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); 101 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
102
101 if (!String.IsNullOrEmpty(m_password)) 103 if (!String.IsNullOrEmpty(m_password))
102 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false); 104 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
105
103 m_region = new RegionState(scene, m_config); 106 m_region = new RegionState(scene, m_config);
104 lock (m_regions) m_regions.Add(m_region); 107 lock (m_regions) m_regions.Add(m_region);
105 m_region.Open(); 108 m_region.Open();
@@ -123,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
123 126
124 public void RemoveRegion(Scene scene) 127 public void RemoveRegion(Scene scene)
125 { 128 {
126 if (!m_pluginEnabled) 129 if (!Enabled)
127 return; 130 return;
128 131
129 if (m_region == null) 132 if (m_region == null)
@@ -150,12 +153,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
150 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry"); 153 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry");
151 154
152 XmlRpcResponse response = new XmlRpcResponse(); 155 XmlRpcResponse response = new XmlRpcResponse();
153 Hashtable responseData = new Hashtable(); 156 Hashtable responseData = new Hashtable();
154 157
155 try 158 try
156 { 159 {
157 Hashtable requestData = (Hashtable)request.Params[0]; 160 Hashtable requestData = (Hashtable)request.Params[0];
158 bool found = false; 161 bool found = false;
159 string region = String.Empty; 162 string region = String.Empty;
160 163
161 if (m_password != String.Empty) 164 if (m_password != String.Empty)
@@ -169,18 +172,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
169 if (!requestData.ContainsKey("region")) 172 if (!requestData.ContainsKey("region"))
170 throw new Exception("No region name specified"); 173 throw new Exception("No region name specified");
171 region = (string)requestData["region"]; 174 region = (string)requestData["region"];
172 175
173 foreach (RegionState rs in m_regions) 176 foreach (RegionState rs in m_regions)
174 { 177 {
175 if (rs.Region == region) 178 if (rs.Region == region)
176 { 179 {
177 responseData["server"] = rs.cs.Server; 180 responseData["server"] = rs.cs.Server;
178 responseData["port"] = (int)rs.cs.Port; 181 responseData["port"] = (int)rs.cs.Port;
179 responseData["user"] = rs.cs.User; 182 responseData["user"] = rs.cs.User;
180 responseData["channel"] = rs.cs.IrcChannel; 183 responseData["channel"] = rs.cs.IrcChannel;
181 responseData["enabled"] = rs.cs.irc.Enabled; 184 responseData["enabled"] = rs.cs.irc.Enabled;
182 responseData["connected"] = rs.cs.irc.Connected; 185 responseData["connected"] = rs.cs.irc.Connected;
183 responseData["nickname"] = rs.cs.irc.Nick; 186 responseData["nickname"] = rs.cs.irc.Nick;
184 found = true; 187 found = true;
185 break; 188 break;
186 } 189 }
@@ -195,7 +198,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message); 198 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
196 199
197 responseData["success"] = "false"; 200 responseData["success"] = "false";
198 responseData["error"] = e.Message; 201 responseData["error"] = e.Message;
199 } 202 }
200 finally 203 finally
201 { 204 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index a014798..c5cba8e 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -53,16 +53,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
53 // Local constants 53 // Local constants
54 54
55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
56 private static readonly char[] CS_SPACE = { ' ' }; 56 private static readonly char[] CS_SPACE = { ' ' };
57 57
58 private const int WD_INTERVAL = 1000; // base watchdog interval 58 private const int WD_INTERVAL = 1000; // base watchdog interval
59 private static int PING_PERIOD = 15; // WD intervals per PING 59 private static int PING_PERIOD = 15; // WD intervals per PING
60 private static int ICCD_PERIOD = 10; // WD intervals between Connects 60 private static int ICCD_PERIOD = 10; // WD intervals between Connects
61 private static int L_TIMEOUT = 25; // Login time out interval 61 private static int L_TIMEOUT = 25; // Login time out interval
62 62
63 private static int _idk_ = 0; // core connector identifier 63 private static int _idk_ = 0; // core connector identifier
64 private static int _pdk_ = 0; // ping interval counter 64 private static int _pdk_ = 0; // ping interval counter
65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter 65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter
66 66
67 // List of configured connectors 67 // List of configured connectors
68 68
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
113 113
114 private Object msyncConnect = new Object(); 114 private Object msyncConnect = new Object();
115 115
116 internal bool m_randomizeNick = true; // add random suffix 116 internal bool m_randomizeNick = true; // add random suffix
117 internal string m_baseNick = null; // base name for randomizing 117 internal string m_baseNick = null; // base name for randomizing
118 internal string m_nick = null; // effective nickname 118 internal string m_nick = null; // effective nickname
119 119
@@ -122,7 +122,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
122 get { return m_nick; } 122 get { return m_nick; }
123 set { m_nick = value; } 123 set { m_nick = value; }
124 } 124 }
125 125
126 private bool m_enabled = false; // connector enablement 126 private bool m_enabled = false; // connector enablement
127 public bool Enabled 127 public bool Enabled
128 { 128 {
@@ -130,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
130 } 130 }
131 131
132 private bool m_connected = false; // connection status 132 private bool m_connected = false; // connection status
133 private bool m_pending = false; // login disposition 133 private bool m_pending = false; // login disposition
134 private int m_timeout = L_TIMEOUT; // login timeout counter 134 private int m_timeout = L_TIMEOUT; // login timeout counter
135 public bool Connected 135 public bool Connected
136 { 136 {
137 get { return m_connected; } 137 get { return m_connected; }
@@ -143,9 +143,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
143 get { return m_ircChannel; } 143 get { return m_ircChannel; }
144 set { m_ircChannel = value; } 144 set { m_ircChannel = value; }
145 } 145 }
146 146
147 private uint m_port = 6667; // session port 147 private uint m_port = 6667; // session port
148 public uint Port 148 public uint Port
149 { 149 {
150 get { return m_port; } 150 get { return m_port; }
151 set { m_port = value; } 151 set { m_port = value; }
@@ -172,10 +172,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
172 172
173 // Network interface 173 // Network interface
174 174
175 private TcpClient m_tcp; 175 private TcpClient m_tcp;
176 private NetworkStream m_stream = null; 176 private NetworkStream m_stream = null;
177 private StreamReader m_reader; 177 private StreamReader m_reader;
178 private StreamWriter m_writer; 178 private StreamWriter m_writer;
179 179
180 // Channel characteristic info (if available) 180 // Channel characteristic info (if available)
181 181
@@ -193,26 +193,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
193 193
194 // Prepare network interface 194 // Prepare network interface
195 195
196 m_tcp = null; 196 m_tcp = null;
197 m_writer = null; 197 m_writer = null;
198 m_reader = null; 198 m_reader = null;
199 199
200 // Setup IRC session parameters 200 // Setup IRC session parameters
201 201
202 m_server = cs.Server; 202 m_server = cs.Server;
203 m_password = cs.Password; 203 m_password = cs.Password;
204 m_baseNick = cs.BaseNickname; 204 m_baseNick = cs.BaseNickname;
205 m_randomizeNick = cs.RandomizeNickname; 205 m_randomizeNick = cs.RandomizeNickname;
206 m_ircChannel = cs.IrcChannel; 206 m_ircChannel = cs.IrcChannel;
207 m_port = cs.Port; 207 m_port = cs.Port;
208 m_user = cs.User; 208 m_user = cs.User;
209 209
210 if (m_watchdog == null) 210 if (m_watchdog == null)
211 { 211 {
212 // Non-differentiating 212 // Non-differentiating
213 213
214 ICCD_PERIOD = cs.ConnectDelay; 214 ICCD_PERIOD = cs.ConnectDelay;
215 PING_PERIOD = cs.PingDelay; 215 PING_PERIOD = cs.PingDelay;
216 216
217 // Smaller values are not reasonable 217 // Smaller values are not reasonable
218 218
@@ -235,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
235 235
236 if (m_randomizeNick) 236 if (m_randomizeNick)
237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
238 else 238 else
239 m_nick = m_baseNick; 239 m_nick = m_baseNick;
240 240
241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); 241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
@@ -295,18 +295,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
295 m_nick, m_ircChannel, m_server)); 295 m_nick, m_ircChannel, m_server));
296 m_writer.Flush(); 296 m_writer.Flush();
297 } 297 }
298 catch (Exception) {} 298 catch (Exception) { }
299 299
300 300
301 m_connected = false; 301 m_connected = false;
302 302
303 try { m_writer.Close(); } catch (Exception) {} 303 try { m_writer.Close(); }
304 try { m_reader.Close(); } catch (Exception) {} 304 catch (Exception) { }
305 try { m_stream.Close(); } catch (Exception) {} 305 try { m_reader.Close(); }
306 try { m_tcp.Close(); } catch (Exception) {} 306 catch (Exception) { }
307 try { m_stream.Close(); }
308 catch (Exception) { }
309 try { m_tcp.Close(); }
310 catch (Exception) { }
307 311
308 } 312 }
309 313
310 lock (m_connectors) 314 lock (m_connectors)
311 m_connectors.Remove(this); 315 m_connectors.Remove(this);
312 316
@@ -347,15 +351,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
347 if (m_connected) return; 351 if (m_connected) return;
348 352
349 m_connected = true; 353 m_connected = true;
350 m_pending = true; 354 m_pending = true;
351 m_timeout = L_TIMEOUT; 355 m_timeout = L_TIMEOUT;
352 356
353 m_tcp = new TcpClient(m_server, (int)m_port); 357 m_tcp = new TcpClient(m_server, (int)m_port);
354 m_stream = m_tcp.GetStream(); 358 m_stream = m_tcp.GetStream();
355 m_reader = new StreamReader(m_stream); 359 m_reader = new StreamReader(m_stream);
356 m_writer = new StreamWriter(m_stream); 360 m_writer = new StreamWriter(m_stream);
357 361
358 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); 362 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
359 363
360 m_listener = new Thread(new ThreadStart(ListenerRun)); 364 m_listener = new Thread(new ThreadStart(ListenerRun));
361 m_listener.Name = "IRCConnectorListenerThread"; 365 m_listener.Name = "IRCConnectorListenerThread";
@@ -418,12 +422,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
418 // the socket and it will disappear of its own accord, once this 422 // the socket and it will disappear of its own accord, once this
419 // processing is completed. 423 // processing is completed.
420 424
421 try { m_writer.Close(); } catch (Exception) {} 425 try { m_writer.Close(); }
422 try { m_reader.Close(); } catch (Exception) {} 426 catch (Exception) { }
423 try { m_tcp.Close(); } catch (Exception) {} 427 try { m_reader.Close(); }
428 catch (Exception) { }
429 try { m_tcp.Close(); }
430 catch (Exception) { }
424 431
425 m_connected = false; 432 m_connected = false;
426 m_pending = false; 433 m_pending = false;
427 m_resetk++; 434 m_resetk++;
428 435
429 } 436 }
@@ -495,7 +502,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
495 { 502 {
496 503
497 string inputLine; 504 string inputLine;
498 int resetk = m_resetk; 505 int resetk = m_resetk;
499 506
500 try 507 try
501 { 508 {
@@ -555,7 +562,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
555 Reconnect(); 562 Reconnect();
556 } 563 }
557 564
558 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", 565 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
559 RegexOptions.Multiline); 566 RegexOptions.Multiline);
560 567
561 private Dictionary<string, string> ExtractMsg(string input) 568 private Dictionary<string, string> ExtractMsg(string input)
@@ -617,8 +624,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
617 string[] commArgs; 624 string[] commArgs;
618 string c_server = m_server; 625 string c_server = m_server;
619 626
620 string pfx = String.Empty; 627 string pfx = String.Empty;
621 string cmd = String.Empty; 628 string cmd = String.Empty;
622 string parms = String.Empty; 629 string parms = String.Empty;
623 630
624 // ":" indicates that a prefix is present 631 // ":" indicates that a prefix is present
@@ -627,15 +634,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
627 // ":" indicates that the remainder of the 634 // ":" indicates that the remainder of the
628 // line is a single parameter value. 635 // line is a single parameter value.
629 636
630 commArgs = command.Split(CS_SPACE,2); 637 commArgs = command.Split(CS_SPACE, 2);
631 638
632 if (commArgs[0].StartsWith(":")) 639 if (commArgs[0].StartsWith(":"))
633 { 640 {
634 pfx = commArgs[0].Substring(1); 641 pfx = commArgs[0].Substring(1);
635 commArgs = commArgs[1].Split(CS_SPACE,2); 642 commArgs = commArgs[1].Split(CS_SPACE, 2);
636 } 643 }
637 644
638 cmd = commArgs[0]; 645 cmd = commArgs[0];
639 parms = commArgs[1]; 646 parms = commArgs[1];
640 647
641 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); 648 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
@@ -646,44 +653,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
646 // Messages 001-004 are always sent 653 // Messages 001-004 are always sent
647 // following signon. 654 // following signon.
648 655
649 case "001" : // Welcome ... 656 case "001": // Welcome ...
650 case "002" : // Server information 657 case "002": // Server information
651 case "003" : // Welcome ... 658 case "003": // Welcome ...
652 break; 659 break;
653 case "004" : // Server information 660 case "004": // Server information
654 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 661 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
655 commArgs = parms.Split(CS_SPACE); 662 commArgs = parms.Split(CS_SPACE);
656 c_server = commArgs[1]; 663 c_server = commArgs[1];
657 m_server = c_server; 664 m_server = c_server;
658 version = commArgs[2]; 665 version = commArgs[2];
659 usermod = commArgs[3]; 666 usermod = commArgs[3];
660 chanmod = commArgs[4]; 667 chanmod = commArgs[4];
661 break; 668 break;
662 case "005" : // Server information 669 case "005": // Server information
663 break; 670 break;
664 case "042" : 671 case "042":
665 case "250" : 672 case "250":
666 case "251" : 673 case "251":
667 case "252" : 674 case "252":
668 case "254" : 675 case "254":
669 case "255" : 676 case "255":
670 case "265" : 677 case "265":
671 case "266" : 678 case "266":
672 case "332" : // Subject 679 case "332": // Subject
673 case "333" : // Subject owner (?) 680 case "333": // Subject owner (?)
674 case "353" : // Name list 681 case "353": // Name list
675 case "366" : // End-of-Name list marker 682 case "366": // End-of-Name list marker
676 case "372" : // MOTD body 683 case "372": // MOTD body
677 case "375" : // MOTD start 684 case "375": // MOTD start
678 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 685 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
679 break; 686 break;
680 case "376" : // MOTD end 687 case "376": // MOTD end
681 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 688 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
682 motd = true; 689 motd = true;
683 break; 690 break;
684 case "451" : // Not registered 691 case "451": // Not registered
685 break; 692 break;
686 case "433" : // Nickname in use 693 case "433": // Nickname in use
687 // Gen a new name 694 // Gen a new name
688 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 695 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
689 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick); 696 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
@@ -695,29 +702,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
695 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); 702 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
696 m_writer.Flush(); 703 m_writer.Flush();
697 break; 704 break;
698 case "479" : // Bad channel name, etc. This will never work, so disable the connection 705 case "479": // Bad channel name, etc. This will never work, so disable the connection
699 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 706 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); 707 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
701 m_enabled = false; 708 m_enabled = false;
702 m_connected = false; 709 m_connected = false;
703 m_pending = false; 710 m_pending = false;
704 break; 711 break;
705 case "NOTICE" : 712 case "NOTICE":
706 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 713 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
707 break; 714 break;
708 case "ERROR" : 715 case "ERROR":
709 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 716 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
710 if (parms.Contains("reconnect too fast")) 717 if (parms.Contains("reconnect too fast"))
711 ICCD_PERIOD++; 718 ICCD_PERIOD++;
712 m_pending = false; 719 m_pending = false;
713 Reconnect(); 720 Reconnect();
714 break; 721 break;
715 case "PING" : 722 case "PING":
716 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 723 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
717 m_writer.WriteLine(String.Format("PONG {0}", parms)); 724 m_writer.WriteLine(String.Format("PONG {0}", parms));
718 m_writer.Flush(); 725 m_writer.Flush();
719 break; 726 break;
720 case "PONG" : 727 case "PONG":
721 break; 728 break;
722 case "JOIN": 729 case "JOIN":
723 if (m_pending) 730 if (m_pending)
@@ -748,19 +755,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
748 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 755 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
749 eventIrcQuit(pfx, cmd, parms); 756 eventIrcQuit(pfx, cmd, parms);
750 break; 757 break;
751 default : 758 default:
752 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); 759 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
753 break; 760 break;
754 } 761 }
755 762
756 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); 763 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
757 764
758 } 765 }
759 766
760 public void eventIrcJoin(string prefix, string command, string parms) 767 public void eventIrcJoin(string prefix, string command, string parms)
761 { 768 {
762 string[] args = parms.Split(CS_SPACE,2); 769 string[] args = parms.Split(CS_SPACE, 2);
763 string IrcUser = prefix.Split('!')[0]; 770 string IrcUser = prefix.Split('!')[0];
764 string IrcChannel = args[0]; 771 string IrcChannel = args[0];
765 772
766 if (IrcChannel.StartsWith(":")) 773 if (IrcChannel.StartsWith(":"))
@@ -772,8 +779,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
772 779
773 public void eventIrcPart(string prefix, string command, string parms) 780 public void eventIrcPart(string prefix, string command, string parms)
774 { 781 {
775 string[] args = parms.Split(CS_SPACE,2); 782 string[] args = parms.Split(CS_SPACE, 2);
776 string IrcUser = prefix.Split('!')[0]; 783 string IrcUser = prefix.Split('!')[0];
777 string IrcChannel = args[0]; 784 string IrcChannel = args[0];
778 785
779 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); 786 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
@@ -782,7 +789,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
782 789
783 public void eventIrcMode(string prefix, string command, string parms) 790 public void eventIrcMode(string prefix, string command, string parms)
784 { 791 {
785 string[] args = parms.Split(CS_SPACE,2); 792 string[] args = parms.Split(CS_SPACE, 2);
786 string UserMode = args[1]; 793 string UserMode = args[1];
787 794
788 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); 795 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
@@ -794,7 +801,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
794 801
795 public void eventIrcNickChange(string prefix, string command, string parms) 802 public void eventIrcNickChange(string prefix, string command, string parms)
796 { 803 {
797 string[] args = parms.Split(CS_SPACE,2); 804 string[] args = parms.Split(CS_SPACE, 2);
798 string UserOldNick = prefix.Split('!')[0]; 805 string UserOldNick = prefix.Split('!')[0];
799 string UserNewNick = args[0].Remove(0, 1); 806 string UserNewNick = args[0].Remove(0, 1);
800 807
@@ -804,11 +811,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
804 811
805 public void eventIrcKick(string prefix, string command, string parms) 812 public void eventIrcKick(string prefix, string command, string parms)
806 { 813 {
807 string[] args = parms.Split(CS_SPACE,3); 814 string[] args = parms.Split(CS_SPACE, 3);
808 string UserKicker = prefix.Split('!')[0]; 815 string UserKicker = prefix.Split('!')[0];
809 string IrcChannel = args[0]; 816 string IrcChannel = args[0];
810 string UserKicked = args[1]; 817 string UserKicked = args[1];
811 string KickMessage = args[2]; 818 string KickMessage = args[2];
812 819
813 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); 820 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
814 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); 821 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
@@ -822,7 +829,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
822 829
823 public void eventIrcQuit(string prefix, string command, string parms) 830 public void eventIrcQuit(string prefix, string command, string parms)
824 { 831 {
825 string IrcUser = prefix.Split('!')[0]; 832 string IrcUser = prefix.Split('!')[0];
826 string QuitMessage = parms; 833 string QuitMessage = parms;
827 834
828 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); 835 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
@@ -842,65 +849,65 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
842 849
843 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); 850 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_);
844 851
845 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger 852 _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger
846 _icc_++; // increment the inter-consecutive-connect-delay counter 853 _icc_++; // increment the inter-consecutive-connect-delay counter
847 854
848 lock (m_connectors) 855 lock (m_connectors)
849 foreach (IRCConnector connector in m_connectors) 856 foreach (IRCConnector connector in m_connectors)
850 { 857 {
851 858
852 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); 859 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector);
853 860
854 if (connector.Enabled) 861 if (connector.Enabled)
855 {
856 if (!connector.Connected)
857 { 862 {
858 try 863 if (!connector.Connected)
859 { 864 {
860 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); 865 try
861 connector.Connect(); 866 {
867 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
868 connector.Connect();
869 }
870 catch (Exception e)
871 {
872 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
873 }
862 } 874 }
863 catch (Exception e) 875 else
864 { 876 {
865 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
866 }
867 }
868 else
869 {
870 877
871 if (connector.m_pending) 878 if (connector.m_pending)
872 {
873 if (connector.m_timeout == 0)
874 { 879 {
875 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); 880 if (connector.m_timeout == 0)
876 connector.Reconnect(); 881 {
882 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
883 connector.Reconnect();
884 }
885 else
886 connector.m_timeout--;
877 } 887 }
878 else
879 connector.m_timeout--;
880 }
881 888
882 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long 889 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long
883 // time, in which case the watch dog might try to ping the server before the socket has been 890 // time, in which case the watch dog might try to ping the server before the socket has been
884 // set up, with nasty side-effects. 891 // set up, with nasty side-effects.
885 892
886 else if (_pdk_ == 0) 893 else if (_pdk_ == 0)
887 {
888 try
889 {
890 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
891 connector.m_writer.Flush();
892 }
893 catch (Exception e)
894 { 894 {
895 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); 895 try
896 m_log.Debug(e); 896 {
897 connector.Reconnect(); 897 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
898 connector.m_writer.Flush();
899 }
900 catch (Exception e)
901 {
902 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
903 m_log.Debug(e);
904 connector.Reconnect();
905 }
898 } 906 }
899 }
900 907
908 }
901 } 909 }
902 } 910 }
903 }
904 911
905 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); 912 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
906 913
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
index 53b103e..d4fe5e0 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -41,49 +41,71 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
41 41
42 internal class RegionState 42 internal class RegionState
43 { 43 {
44
45 private static readonly ILog m_log = 44 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 46
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 47 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
49 private const int DEBUG_CHANNEL = 2147483647; 48 private const int DEBUG_CHANNEL = 2147483647;
50 49
51 private static int _idk_ = 0; 50 private static int _idk_ = 0;
52 51
53 // Runtime variables; these values are assigned when the 52 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter. 53 // IrcState is created and remain constant thereafter.
55 54
56 internal string Region = String.Empty; 55 internal string Region = String.Empty;
57 internal string Host = String.Empty; 56 internal string Host = String.Empty;
58 internal string LocX = String.Empty; 57 internal string LocX = String.Empty;
59 internal string LocY = String.Empty; 58 internal string LocY = String.Empty;
60 internal string IDK = String.Empty; 59 internal string IDK = String.Empty;
61 60
62 // System values - used only be the IRC classes themselves 61 // System values - used only be the IRC classes themselves
63 62
64 internal ChannelState cs = null; // associated IRC configuration 63 internal ChannelState cs = null; // associated IRC configuration
65 internal Scene scene = null; // associated scene 64 internal Scene scene = null; // associated scene
66 internal IConfig config = null; // configuration file reference 65 internal IConfig config = null; // configuration file reference
67 internal bool enabled = true; 66 internal bool enabled = true;
68 67
68 //AgentAlert
69 internal bool showAlert = false;
70 internal string alertMessage = String.Empty;
71 internal IDialogModule dialogModule = null;
72
69 // This list is used to keep track of who is here, and by 73 // This list is used to keep track of who is here, and by
70 // implication, who is not. 74 // implication, who is not.
71 75
72 internal List<IClientAPI> clients = new List<IClientAPI>(); 76 internal List<IClientAPI> clients = new List<IClientAPI>();
73 77
74 // Setup runtime variable values 78 // Setup runtime variable values
75 79
76 public RegionState(Scene p_scene, IConfig p_config) 80 public RegionState(Scene p_scene, IConfig p_config)
77 { 81 {
78 82 scene = p_scene;
79 scene = p_scene;
80 config = p_config; 83 config = p_config;
81 84
82 Region = scene.RegionInfo.RegionName; 85 Region = scene.RegionInfo.RegionName;
83 Host = scene.RegionInfo.ExternalHostName; 86 Host = scene.RegionInfo.ExternalHostName;
84 LocX = Convert.ToString(scene.RegionInfo.RegionLocX); 87 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
85 LocY = Convert.ToString(scene.RegionInfo.RegionLocY); 88 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
86 IDK = Convert.ToString(_idk_++); 89 IDK = Convert.ToString(_idk_++);
90
91 showAlert = config.GetBoolean("alert_show", false);
92 string alertServerInfo = String.Empty;
93
94 if (showAlert)
95 {
96 bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true);
97
98 if (showAlertServerInfo)
99 alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n",
100 config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", ""));
101
102 string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc.");
103 string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened.");
104
105 alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage);
106
107 dialogModule = scene.RequestModuleInterface<IDialogModule>();
108 }
87 109
88 // OpenChannel conditionally establishes a connection to the 110 // OpenChannel conditionally establishes a connection to the
89 // IRC server. The request will either succeed, or it will 111 // IRC server. The request will either succeed, or it will
@@ -93,9 +115,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
93 115
94 // Connect channel to world events 116 // Connect channel to world events
95 117
96 scene.EventManager.OnChatFromWorld += OnSimChat; 118 scene.EventManager.OnChatFromWorld += OnSimChat;
97 scene.EventManager.OnChatFromClient += OnSimChat; 119 scene.EventManager.OnChatFromClient += OnSimChat;
98 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; 120 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
99 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; 121 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
100 122
101 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); 123 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
@@ -106,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
106 128
107 ~RegionState() 129 ~RegionState()
108 { 130 {
109 if (cs != null) 131 if (cs != null)
110 cs.RemoveRegion(this); 132 cs.RemoveRegion(this);
111 } 133 }
112 134
113 // Called by PostInitialize after all regions have been created 135 // Called by PostInitialize after all regions have been created
@@ -138,7 +160,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
138 { 160 {
139 if (clients.Contains(client)) 161 if (clients.Contains(client))
140 { 162 {
141 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 163 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
142 { 164 {
143 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); 165 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
144 //Check if this person is excluded from IRC 166 //Check if this person is excluded from IRC
@@ -147,7 +169,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
147 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); 169 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
148 } 170 }
149 } 171 }
150 client.OnLogout -= OnClientLoggedOut; 172 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut; 173 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client); 174 clients.Remove(client);
153 } 175 }
@@ -171,13 +193,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
171 { 193 {
172 if (clients.Contains(client)) 194 if (clients.Contains(client))
173 { 195 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 196 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 { 197 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 198 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); 199 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); 200 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 } 201 }
180 client.OnLogout -= OnClientLoggedOut; 202 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut; 203 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client); 204 clients.Remove(client);
183 } 205 }
@@ -195,14 +217,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 217
196 private void OnMakeRootAgent(ScenePresence presence) 218 private void OnMakeRootAgent(ScenePresence presence)
197 { 219 {
198
199 IClientAPI client = presence.ControllingClient; 220 IClientAPI client = presence.ControllingClient;
200 221
201 try 222 try
202 { 223 {
203 if (!clients.Contains(client)) 224 if (!clients.Contains(client))
204 { 225 {
205 client.OnLogout += OnClientLoggedOut; 226 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut; 227 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client); 228 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 229 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
@@ -216,17 +237,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
216 } 237 }
217 } 238 }
218 } 239 }
240
241 if (dialogModule != null && showAlert)
242 dialogModule.SendAlertToUser(client, alertMessage, true);
219 } 243 }
220 catch (Exception ex) 244 catch (Exception ex)
221 { 245 {
222 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); 246 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
223 m_log.Debug(ex); 247 m_log.Debug(ex);
224 } 248 }
225
226 } 249 }
227 250
228 // This handler detects chat events int he virtual world. 251 // This handler detects chat events int he virtual world.
229
230 public void OnSimChat(Object sender, OSChatMessage msg) 252 public void OnSimChat(Object sender, OSChatMessage msg)
231 { 253 {
232 254
@@ -317,14 +339,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
317 // that evident. 339 // that evident.
318 340
319 default: 341 default:
320 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", 342 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
321 Region, msg.Message); 343 Region, msg.Message);
322 cs.irc.Send(msg.Message); 344 cs.irc.Send(msg.Message);
323 break; 345 break;
324 } 346 }
325 } 347 }
326 catch (Exception ex) 348 catch (Exception ex)
327 { 349 {
328 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", 350 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
329 Region, ex.Message); 351 Region, ex.Message);
330 m_log.Debug(ex); 352 m_log.Debug(ex);
@@ -366,7 +388,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
366 388
367 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); 389 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
368 390
369 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) 391 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
370 { 392 {
371 string txt = msg.Message; 393 string txt = msg.Message;
372 if (txt.StartsWith("/me ")) 394 if (txt.StartsWith("/me "))
@@ -376,13 +398,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
376 return; 398 return;
377 } 399 }
378 400
379 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && 401 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
380 msg.Channel == cs.RelayChannelOut) 402 msg.Channel == cs.RelayChannelOut)
381 { 403 {
382 Match m = cs.AccessPasswordRegex.Match(msg.Message); 404 Match m = cs.AccessPasswordRegex.Match(msg.Message);
383 if (null != m) 405 if (null != m)
384 { 406 {
385 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), 407 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
386 m.Groups["message"].ToString()); 408 m.Groups["message"].ToString());
387 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), 409 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
388 scene.RegionInfo.RegionName, m.Groups["message"].ToString()); 410 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index f292a75..0cec959 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -551,13 +551,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
551 reqStream.Close(); 551 reqStream.Close();
552 } 552 }
553 553
554 HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse(); 554 using (HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse())
555 Encoding encoding = Util.UTF8; 555 {
556 StreamReader fwdresponsestream = new StreamReader(fwdrsp.GetResponseStream(), encoding); 556 Encoding encoding = Util.UTF8;
557 fwdresponsestr = fwdresponsestream.ReadToEnd(); 557
558 fwdresponsecontenttype = fwdrsp.ContentType; 558 using (Stream s = fwdrsp.GetResponseStream())
559 fwdresponsecode = (int)fwdrsp.StatusCode; 559 {
560 fwdresponsestream.Close(); 560 using (StreamReader fwdresponsestream = new StreamReader(s))
561 {
562 fwdresponsestr = fwdresponsestream.ReadToEnd();
563 fwdresponsecontenttype = fwdrsp.ContentType;
564 fwdresponsecode = (int)fwdrsp.StatusCode;
565 }
566 }
567 }
561 568
562 response["content_type"] = fwdresponsecontenttype; 569 response["content_type"] = fwdresponsecontenttype;
563 response["str_response_string"] = fwdresponsestr; 570 response["str_response_string"] = fwdresponsestr;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index 7da1de6..e756c70 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -1123,18 +1123,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1123 // Otherwise prepare the request 1123 // Otherwise prepare the request
1124// m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); 1124// m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl);
1125 1125
1126 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); 1126 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl);
1127 HttpWebResponse rsp = null;
1128 1127
1129 // We are sending just parameters, no content 1128 // We are sending just parameters, no content
1130 req.ContentLength = 0; 1129 req.ContentLength = 0;
1131 1130
1132 // Send request and retrieve the response 1131 // Send request and retrieve the response
1133 rsp = (HttpWebResponse)req.GetResponse(); 1132 using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse())
1134 1133 using (Stream s = rsp.GetResponseStream())
1135 XmlTextReader rdr = new XmlTextReader(rsp.GetResponseStream()); 1134 using (XmlTextReader rdr = new XmlTextReader(s))
1136 doc.Load(rdr); 1135 doc.Load(rdr);
1137 rdr.Close();
1138 } 1136 }
1139 catch (Exception e) 1137 catch (Exception e)
1140 { 1138 {
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..71b24ac 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
@@ -1151,28 +1146,38 @@ namespace Nwc.XmlRpc
1151 request.AllowWriteStreamBuffering = true; 1146 request.AllowWriteStreamBuffering = true;
1152 request.KeepAlive = !_disableKeepAlive; 1147 request.KeepAlive = !_disableKeepAlive;
1153 1148
1154 Stream stream = request.GetRequestStream(); 1149 using (Stream stream = request.GetRequestStream())
1155 XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII);
1156 _serializer.Serialize(xml, this);
1157 xml.Flush();
1158 xml.Close();
1159
1160 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
1161 StreamReader input = new StreamReader(response.GetResponseStream());
1162
1163 string inputXml = input.ReadToEnd();
1164 XmlRpcResponse resp;
1165 try
1166 { 1150 {
1167 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); 1151 using (XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII))
1152 {
1153 _serializer.Serialize(xml, this);
1154 xml.Flush();
1155 }
1168 } 1156 }
1169 catch (Exception e) 1157
1158 XmlRpcResponse resp;
1159
1160 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
1170 { 1161 {
1171 RequestResponse = inputXml; 1162 using (Stream s = response.GetResponseStream())
1172 throw e; 1163 {
1164 using (StreamReader input = new StreamReader(s))
1165 {
1166 string inputXml = input.ReadToEnd();
1167
1168 try
1169 {
1170 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml);
1171 }
1172 catch (Exception e)
1173 {
1174 RequestResponse = inputXml;
1175 throw e;
1176 }
1177 }
1178 }
1173 } 1179 }
1174 input.Close(); 1180
1175 response.Close();
1176 return resp; 1181 return resp;
1177 } 1182 }
1178 } 1183 }
diff --git a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
index 7d37135..0615036 100644
--- a/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
+++ b/OpenSim/Region/OptionalModules/Example/BareBonesNonShared/BareBonesNonSharedModule.cs
@@ -33,6 +33,12 @@ using Nini.Config;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35 35
36// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
37// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
38// the available DLLs
39//[assembly: Addin("MyModule", "1.0")]
40//[assembly: AddinDependency("OpenSim", "0.5")]
41
36namespace OpenSim.Region.OptionalModules.Example.BareBonesNonShared 42namespace OpenSim.Region.OptionalModules.Example.BareBonesNonShared
37{ 43{
38 /// <summary> 44 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs b/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
index 781fe95..811a263 100644
--- a/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
+++ b/OpenSim/Region/OptionalModules/Example/BareBonesShared/BareBonesSharedModule.cs
@@ -33,6 +33,12 @@ using Nini.Config;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35 35
36// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already
37// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans
38// the available DLLs
39//[assembly: Addin("MyModule", "1.0")]
40//[assembly: AddinDependency("OpenSim", "0.5")]
41
36namespace OpenSim.Region.OptionalModules.Example.BareBonesShared 42namespace OpenSim.Region.OptionalModules.Example.BareBonesShared
37{ 43{
38 /// <summary> 44 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs
new file mode 100644
index 0000000..5bf0ed4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.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 copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenSim.Framework.Servers;
32using Mono.Addins;
33using log4net;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38using OpenSim.Framework.Servers.HttpServer;
39
40
41namespace OpenSim.Region.OptionalModules.WebSocketEchoModule
42{
43
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebSocketEchoModule")]
45 public class WebSocketEchoModule : ISharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private bool enabled;
50 public string Name { get { return "WebSocketEchoModule"; } }
51
52 public Type ReplaceableInterface { get { return null; } }
53
54
55 private HashSet<WebSocketHttpServerHandler> _activeHandlers = new HashSet<WebSocketHttpServerHandler>();
56
57 public void Initialise(IConfigSource pConfig)
58 {
59 enabled = (pConfig.Configs["WebSocketEcho"] != null);
60// if (enabled)
61// m_log.DebugFormat("[WebSocketEchoModule]: INITIALIZED MODULE");
62 }
63
64 /// <summary>
65 /// This method sets up the callback to WebSocketHandlerCallback below when a HTTPRequest comes in for /echo
66 /// </summary>
67 public void PostInitialise()
68 {
69 if (enabled)
70 MainServer.Instance.AddWebSocketHandler("/echo", WebSocketHandlerCallback);
71 }
72
73 // This gets called by BaseHttpServer and gives us an opportunity to set things on the WebSocket handler before we turn it on
74 public void WebSocketHandlerCallback(string path, WebSocketHttpServerHandler handler)
75 {
76 SubscribeToEvents(handler);
77 handler.SetChunksize(8192);
78 handler.NoDelay_TCP_Nagle = true;
79 handler.HandshakeAndUpgrade();
80 }
81
82 //These are our normal events
83 public void SubscribeToEvents(WebSocketHttpServerHandler handler)
84 {
85 handler.OnClose += HandlerOnOnClose;
86 handler.OnText += HandlerOnOnText;
87 handler.OnUpgradeCompleted += HandlerOnOnUpgradeCompleted;
88 handler.OnData += HandlerOnOnData;
89 handler.OnPong += HandlerOnOnPong;
90 }
91
92 public void UnSubscribeToEvents(WebSocketHttpServerHandler handler)
93 {
94 handler.OnClose -= HandlerOnOnClose;
95 handler.OnText -= HandlerOnOnText;
96 handler.OnUpgradeCompleted -= HandlerOnOnUpgradeCompleted;
97 handler.OnData -= HandlerOnOnData;
98 handler.OnPong -= HandlerOnOnPong;
99 }
100
101 private void HandlerOnOnPong(object sender, PongEventArgs pongdata)
102 {
103 m_log.Info("[WebSocketEchoModule]: Got a pong.. ping time: " + pongdata.PingResponseMS);
104 }
105
106 private void HandlerOnOnData(object sender, WebsocketDataEventArgs data)
107 {
108 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
109 obj.SendData(data.Data);
110 m_log.Info("[WebSocketEchoModule]: We received a bunch of ugly non-printable bytes");
111 obj.SendPingCheck();
112 }
113
114
115 private void HandlerOnOnUpgradeCompleted(object sender, UpgradeCompletedEventArgs completeddata)
116 {
117 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
118 _activeHandlers.Add(obj);
119 }
120
121 private void HandlerOnOnText(object sender, WebsocketTextEventArgs text)
122 {
123 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
124 obj.SendMessage(text.Data);
125 m_log.Info("[WebSocketEchoModule]: We received this: " + text.Data);
126 }
127
128 // Remove the references to our handler
129 private void HandlerOnOnClose(object sender, CloseEventArgs closedata)
130 {
131 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
132 UnSubscribeToEvents(obj);
133
134 lock (_activeHandlers)
135 _activeHandlers.Remove(obj);
136 obj.Dispose();
137 }
138
139 // Shutting down.. so shut down all sockets.
140 // Note.. this should be done outside of an ienumerable if you're also hook to the close event.
141 public void Close()
142 {
143 if (!enabled)
144 return;
145
146 // We convert this to a for loop so we're not in in an IEnumerable when the close
147 //call triggers an event which then removes item from _activeHandlers that we're enumerating
148 WebSocketHttpServerHandler[] items = new WebSocketHttpServerHandler[_activeHandlers.Count];
149 _activeHandlers.CopyTo(items);
150
151 for (int i = 0; i < items.Length; i++)
152 {
153 items[i].Close(string.Empty);
154 items[i].Dispose();
155 }
156 _activeHandlers.Clear();
157 MainServer.Instance.RemoveWebSocketHandler("/echo");
158 }
159
160 public void AddRegion(Scene scene)
161 {
162// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName);
163 }
164
165 public void RemoveRegion(Scene scene)
166 {
167// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
168 }
169
170 public void RegionLoaded(Scene scene)
171 {
172// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName);
173 }
174 }
175} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs
new file mode 100644
index 0000000..6e74ce0
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs
@@ -0,0 +1,339 @@
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.Diagnostics;
31using System.Linq;
32using System.Net.NetworkInformation;
33using System.Text;
34using System.Threading;
35
36using log4net;
37using Mono.Addins;
38using Nini.Config;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Console;
42using OpenSim.Framework.Monitoring;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45
46using OpenMetaverse.StructuredData;
47
48namespace OpenSim.Region.OptionalModules.Framework.Monitoring
49{
50[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ServerStatistics")]
51public class ServerStats : ISharedRegionModule
52{
53 private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
54 private readonly string LogHeader = "[SERVER STATS]";
55
56 public bool Enabled = false;
57 private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
58
59 public readonly string CategoryServer = "server";
60
61 public readonly string ContainerProcessor = "processor";
62 public readonly string ContainerMemory = "memory";
63 public readonly string ContainerNetwork = "network";
64 public readonly string ContainerProcess = "process";
65
66 public string NetworkInterfaceTypes = "Ethernet";
67
68 readonly int performanceCounterSampleInterval = 500;
69 int lastperformanceCounterSampleTime = 0;
70
71 private class PerfCounterControl
72 {
73 public PerformanceCounter perfCounter;
74 public int lastFetch;
75 public string name;
76 public PerfCounterControl(PerformanceCounter pPc)
77 : this(pPc, String.Empty)
78 {
79 }
80 public PerfCounterControl(PerformanceCounter pPc, string pName)
81 {
82 perfCounter = pPc;
83 lastFetch = 0;
84 name = pName;
85 }
86 }
87
88 PerfCounterControl processorPercentPerfCounter = null;
89
90 #region ISharedRegionModule
91 // IRegionModuleBase.Name
92 public string Name { get { return "Server Stats"; } }
93 // IRegionModuleBase.ReplaceableInterface
94 public Type ReplaceableInterface { get { return null; } }
95 // IRegionModuleBase.Initialize
96 public void Initialise(IConfigSource source)
97 {
98 IConfig cfg = source.Configs["Monitoring"];
99
100 if (cfg != null)
101 Enabled = cfg.GetBoolean("ServerStatsEnabled", true);
102
103 if (Enabled)
104 {
105 NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet");
106 }
107 }
108 // IRegionModuleBase.Close
109 public void Close()
110 {
111 if (RegisteredStats.Count > 0)
112 {
113 foreach (Stat stat in RegisteredStats.Values)
114 {
115 StatsManager.DeregisterStat(stat);
116 stat.Dispose();
117 }
118 RegisteredStats.Clear();
119 }
120 }
121 // IRegionModuleBase.AddRegion
122 public void AddRegion(Scene scene)
123 {
124 }
125 // IRegionModuleBase.RemoveRegion
126 public void RemoveRegion(Scene scene)
127 {
128 }
129 // IRegionModuleBase.RegionLoaded
130 public void RegionLoaded(Scene scene)
131 {
132 }
133 // ISharedRegionModule.PostInitialize
134 public void PostInitialise()
135 {
136 if (RegisteredStats.Count == 0)
137 {
138 RegisterServerStats();
139 }
140 }
141 #endregion ISharedRegionModule
142
143 private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
144 {
145 string desc = pDesc;
146 if (desc == null)
147 desc = pName;
148 Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info);
149 StatsManager.RegisterStat(stat);
150 RegisteredStats.Add(pName, stat);
151 }
152
153 public void RegisterServerStats()
154 {
155 lastperformanceCounterSampleTime = Util.EnvironmentTickCount();
156 PerformanceCounter tempPC;
157 Stat tempStat;
158 string tempName;
159
160 try
161 {
162 tempName = "CPUPercent";
163 tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total");
164 processorPercentPerfCounter = new PerfCounterControl(tempPC);
165 // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy.
166 tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor,
167 StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); },
168 StatVerbosity.Info);
169 StatsManager.RegisterStat(tempStat);
170 RegisteredStats.Add(tempName, tempStat);
171
172 MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
173 (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
174
175 MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
176 (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
177
178 MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
179 (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
180
181 MakeStat("Threads", null, "threads", ContainerProcessor,
182 (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
183 }
184 catch (Exception e)
185 {
186 m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e);
187 }
188
189 try
190 {
191 List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(','));
192
193 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces();
194 foreach (NetworkInterface nic in nics)
195 {
196 if (nic.OperationalStatus != OperationalStatus.Up)
197 continue;
198
199 string nicInterfaceType = nic.NetworkInterfaceType.ToString();
200 if (!okInterfaceTypes.Contains(nicInterfaceType))
201 {
202 m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
203 LogHeader, nic.Name, nicInterfaceType);
204 m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
205 LogHeader, NetworkInterfaceTypes);
206 continue;
207 }
208
209 if (nic.Supports(NetworkInterfaceComponent.IPv4))
210 {
211 IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
212 if (nicStats != null)
213 {
214 MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
215 (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
216 MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
217 (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
218 MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
219 (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
220 }
221 }
222 // TODO: add IPv6 (it may actually happen someday)
223 }
224 }
225 catch (Exception e)
226 {
227 m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
228 }
229
230 MakeStat("ProcessMemory", null, "MB", ContainerMemory,
231 (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; });
232 MakeStat("ObjectMemory", null, "MB", ContainerMemory,
233 (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; });
234 MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory,
235 (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); });
236 MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory,
237 (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); });
238 }
239
240 // Notes on performance counters:
241 // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
242 // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c
243 // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters
244 private delegate double PerfCounterNextValue();
245 private void GetNextValue(Stat stat, PerfCounterControl perfControl)
246 {
247 GetNextValue(stat, perfControl, 1.0);
248 }
249 private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor)
250 {
251 if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
252 {
253 if (perfControl != null && perfControl.perfCounter != null)
254 {
255 try
256 {
257 // Kludge for factor to run double duty. If -1, subtract the value from one
258 if (factor == -1)
259 stat.Value = 1 - perfControl.perfCounter.NextValue();
260 else
261 stat.Value = perfControl.perfCounter.NextValue() / factor;
262 }
263 catch (Exception e)
264 {
265 m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
266 }
267 perfControl.lastFetch = Util.EnvironmentTickCount();
268 }
269 }
270 }
271
272 // Lookup the nic that goes with this stat and set the value by using a fetch action.
273 // Not sure about closure with delegates inside delegates.
274 private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
275 private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
276 {
277 // Get the one nic that has the name of this stat
278 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where(
279 (network) => network.Name == stat.Description);
280 try
281 {
282 foreach (NetworkInterface nic in nics)
283 {
284 IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
285 if (intrStats != null)
286 {
287 double newVal = Math.Round(getter(intrStats) / factor, 3);
288 stat.Value = newVal;
289 }
290 break;
291 }
292 }
293 catch
294 {
295 // There are times interfaces go away so we just won't update the stat for this
296 m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
297 }
298 }
299}
300
301public class ServerStatsAggregator : Stat
302{
303 public ServerStatsAggregator(
304 string shortName,
305 string name,
306 string description,
307 string unitName,
308 string category,
309 string container
310 )
311 : base(
312 shortName,
313 name,
314 description,
315 unitName,
316 category,
317 container,
318 StatType.Push,
319 MeasuresOfInterest.None,
320 null,
321 StatVerbosity.Info)
322 {
323 }
324 public override string ToConsoleString()
325 {
326 StringBuilder sb = new StringBuilder();
327
328 return sb.ToString();
329 }
330
331 public override OSDMap ToOSDMap()
332 {
333 OSDMap ret = new OSDMap();
334
335 return ret;
336 }
337}
338
339}
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index 40f7fbc..3083a33 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
146 { 146 {
147 foreach (PhysParameterEntry ppe in physScene.GetParameterList()) 147 foreach (PhysParameterEntry ppe in physScene.GetParameterList())
148 { 148 {
149 float val = 0.0f; 149 string val = string.Empty;
150 if (physScene.GetPhysicsParameter(ppe.name, out val)) 150 if (physScene.GetPhysicsParameter(ppe.name, out val))
151 { 151 {
152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val); 152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
@@ -159,7 +159,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
159 } 159 }
160 else 160 else
161 { 161 {
162 float val = 0.0f; 162 string val = string.Empty;
163 if (physScene.GetPhysicsParameter(parm, out val)) 163 if (physScene.GetPhysicsParameter(parm, out val))
164 { 164 {
165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val); 165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
@@ -185,21 +185,12 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
185 return; 185 return;
186 } 186 }
187 string parm = "xxx"; 187 string parm = "xxx";
188 float val = 0f; 188 string valparm = String.Empty;
189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value 189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
190 try 190 try
191 { 191 {
192 parm = cmdparms[2]; 192 parm = cmdparms[2];
193 string valparm = cmdparms[3].ToLower(); 193 valparm = cmdparms[3].ToLower();
194 if (valparm == "true")
195 val = PhysParameterEntry.NUMERIC_TRUE;
196 else
197 {
198 if (valparm == "false")
199 val = PhysParameterEntry.NUMERIC_FALSE;
200 else
201 val = float.Parse(valparm, Culture.NumberFormatInfo);
202 }
203 if (cmdparms.Length > 4) 194 if (cmdparms.Length > 4)
204 { 195 {
205 if (cmdparms[4].ToLower() == "all") 196 if (cmdparms[4].ToLower() == "all")
@@ -224,7 +215,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
224 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; 215 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
225 if (physScene != null) 216 if (physScene != null)
226 { 217 {
227 if (!physScene.SetPhysicsParameter(parm, val, localID)) 218 if (!physScene.SetPhysicsParameter(parm, valparm, localID))
228 { 219 {
229 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName); 220 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
230 } 221 }
diff --git a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
index 39cabb5..a375da9 100644
--- a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
+++ b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
@@ -57,9 +57,10 @@ namespace OpenSim.Region.OptionalModules
57 57
58 public void Initialise(IConfigSource config) 58 public void Initialise(IConfigSource config)
59 { 59 {
60 IConfig myConfig = config.Configs["Startup"]; 60 //IConfig myConfig = config.Configs["Startup"];
61 61
62 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); 62 string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules",
63 new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
63 64
64 List<string> modules=new List<string>(permissionModules.Split(',')); 65 List<string> modules=new List<string>(permissionModules.Split(','));
65 66
diff --git a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
index 217b2d5..70bda72 100644
--- a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs
@@ -30,8 +30,8 @@ using Mono.Addins;
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.7.6.*")]
34[assembly: AssemblyFileVersion("1.0.0.0")] 34
35 35
36[assembly: Addin("OpenSim.Region.OptionalModules", "0.1")] 36[assembly: Addin("OpenSim.Region.OptionalModules", "0.1")]
37[assembly: AddinDependency("OpenSim", "0.5")] 37[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs
new file mode 100755
index 0000000..6009dc5
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs
@@ -0,0 +1,171 @@
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.Linq;
30using System.Reflection;
31using System.Text;
32
33using OpenSim.Framework;
34using OpenSim.Region.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.CoreModules;
38
39using Mono.Addins;
40using Nini.Config;
41using log4net;
42using OpenMetaverse;
43
44namespace OpenSim.Region.OptionalModules.Scripting
45{
46[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
47public class ExtendedPhysics : INonSharedRegionModule
48{
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private static string LogHeader = "[EXTENDED PHYSICS]";
51
52 private IConfig Configuration { get; set; }
53 private bool Enabled { get; set; }
54 private Scene BaseScene { get; set; }
55 private IScriptModuleComms Comms { get; set; }
56
57 #region INonSharedRegionModule
58
59 public string Name { get { return this.GetType().Name; } }
60
61 public void Initialise(IConfigSource config)
62 {
63 BaseScene = null;
64 Enabled = false;
65 Configuration = null;
66 Comms = null;
67
68 try
69 {
70 if ((Configuration = config.Configs["ExtendedPhysics"]) != null)
71 {
72 Enabled = Configuration.GetBoolean("Enabled", Enabled);
73 }
74 }
75 catch (Exception e)
76 {
77 m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e);
78 }
79
80 m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not"));
81 }
82
83 public void Close()
84 {
85 if (BaseScene != null)
86 {
87 BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
88 BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated;
89 BaseScene = null;
90 }
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 }
96
97 public void RemoveRegion(Scene scene)
98 {
99 if (BaseScene != null && BaseScene == scene)
100 {
101 Close();
102 }
103 }
104
105 public void RegionLoaded(Scene scene)
106 {
107 if (!Enabled) return;
108
109 BaseScene = scene;
110
111 Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>();
112 if (Comms == null)
113 {
114 m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader);
115 Enabled = false;
116
117 return;
118 }
119
120 // Register as LSL functions all the [ScriptInvocation] marked methods.
121 Comms.RegisterScriptInvocations(this);
122
123 // When an object is modified, we might need to update its extended physics parameters
124 BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
125 BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated;
126
127 }
128
129 public Type ReplaceableInterface { get { return null; } }
130
131 #endregion // INonSharedRegionModule
132
133 private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
134 {
135 throw new NotImplementedException();
136 }
137
138 // Event generated when some property of a prim changes.
139 private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate)
140 {
141 }
142
143 [ScriptConstant]
144 public static int PHYS_CENTER_OF_MASS = 1 << 0;
145
146 [ScriptConstant]
147 public static int PHYS_LINKSET_TYPE_CONSTRAINT = 1;
148 [ScriptConstant]
149 public static int PHYS_LINKSET_TYPE_COMPOUND = 2;
150 [ScriptConstant]
151 public static int PHYS_LINKSET_TYPE_MANUAL = 3;
152
153 [ScriptInvocation]
154 public string physGetEngineType(UUID hostID, UUID scriptID)
155 {
156 string ret = string.Empty;
157
158 if (BaseScene.PhysicsScene != null)
159 {
160 ret = BaseScene.PhysicsScene.EngineType;
161 }
162
163 return ret;
164 }
165
166 [ScriptInvocation]
167 public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
168 {
169 }
170}
171}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
index 34894ba..e498c6a 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
49 private static readonly ILog m_log = 49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 private OSD m_ValueStore; 52 protected virtual OSD ValueStore { get; set; }
53 53
54 protected class TakeValueCallbackClass 54 protected class TakeValueCallbackClass
55 { 55 {
@@ -68,42 +68,141 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
68 protected List<TakeValueCallbackClass> m_TakeStore; 68 protected List<TakeValueCallbackClass> m_TakeStore;
69 protected List<TakeValueCallbackClass> m_ReadStore; 69 protected List<TakeValueCallbackClass> m_ReadStore;
70 70
71 // add separators for quoted paths and array references
72 protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
71 73
74 // add quotes to bare identifiers which are limited to alphabetic characters
75 protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)");
76
77 // remove extra separator characters
78 protected static Regex m_ParsePassFour = new Regex("\\.+");
79
80 // expression used to validate the full path, this is canonical representation
81 protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$");
82
83 // expression used to match path components
84 protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
85
86 // extract the internals of an array reference
87 protected static Regex m_SimpleArrayPattern = new Regex("^\\[([0-9]+)\\]$");
88 protected static Regex m_ArrayPattern = new Regex("^\\[([0-9]+|\\+)\\]$");
89
90 // extract the internals of a has reference
91 protected static Regex m_HashPattern = new Regex("^{([^}]+)}$");
92
93 // -----------------------------------------------------------------
94 /// <summary>
95 /// This is a simple estimator for the size of the stored data, it
96 /// is not precise, but should be close enough to implement reasonable
97 /// limits on the storage space used
98 /// </summary>
99 // -----------------------------------------------------------------
100 public int StringSpace { get; set; }
101
72 // ----------------------------------------------------------------- 102 // -----------------------------------------------------------------
73 /// <summary> 103 /// <summary>
74 /// 104 ///
75 /// </summary> 105 /// </summary>
76 // ----------------------------------------------------------------- 106 // -----------------------------------------------------------------
77 public JsonStore() : this("") {} 107 public static bool CanonicalPathExpression(string ipath, out string opath)
108 {
109 Stack<string> path;
110 if (! ParsePathExpression(ipath,out path))
111 {
112 opath = "";
113 return false;
114 }
115
116 opath = PathExpressionToKey(path);
117 return true;
118 }
78 119
79 public JsonStore(string value) 120 // -----------------------------------------------------------------
121 /// <summary>
122 ///
123 /// </summary>
124 // -----------------------------------------------------------------
125 public JsonStore()
80 { 126 {
127 StringSpace = 0;
81 m_TakeStore = new List<TakeValueCallbackClass>(); 128 m_TakeStore = new List<TakeValueCallbackClass>();
82 m_ReadStore = new List<TakeValueCallbackClass>(); 129 m_ReadStore = new List<TakeValueCallbackClass>();
83 130 }
131
132 public JsonStore(string value) : this()
133 {
134 // This is going to throw an exception if the value is not
135 // a valid JSON chunk. Calling routines should catch the
136 // exception and handle it appropriately
84 if (String.IsNullOrEmpty(value)) 137 if (String.IsNullOrEmpty(value))
85 m_ValueStore = new OSDMap(); 138 ValueStore = new OSDMap();
86 else 139 else
87 m_ValueStore = OSDParser.DeserializeJson(value); 140 ValueStore = OSDParser.DeserializeJson(value);
88 } 141 }
142
143 // -----------------------------------------------------------------
144 /// <summary>
145 ///
146 /// </summary>
147 // -----------------------------------------------------------------
148 public JsonStoreNodeType GetNodeType(string expr)
149 {
150 Stack<string> path;
151 if (! ParsePathExpression(expr,out path))
152 return JsonStoreNodeType.Undefined;
153
154 OSD result = ProcessPathExpression(ValueStore,path);
89 155
156 if (result == null)
157 return JsonStoreNodeType.Undefined;
158
159 if (result is OSDMap)
160 return JsonStoreNodeType.Object;
161
162 if (result is OSDArray)
163 return JsonStoreNodeType.Array;
164
165 if (OSDBaseType(result.Type))
166 return JsonStoreNodeType.Value;
167
168 return JsonStoreNodeType.Undefined;
169 }
170
90 // ----------------------------------------------------------------- 171 // -----------------------------------------------------------------
91 /// <summary> 172 /// <summary>
92 /// 173 ///
93 /// </summary> 174 /// </summary>
94 // ----------------------------------------------------------------- 175 // -----------------------------------------------------------------
95 public bool TestPath(string expr, bool useJson) 176 public JsonStoreValueType GetValueType(string expr)
96 { 177 {
97 Stack<string> path = ParsePathExpression(expr); 178 Stack<string> path;
98 OSD result = ProcessPathExpression(m_ValueStore,path); 179 if (! ParsePathExpression(expr,out path))
180 return JsonStoreValueType.Undefined;
181
182 OSD result = ProcessPathExpression(ValueStore,path);
99 183
100 if (result == null) 184 if (result == null)
101 return false; 185 return JsonStoreValueType.Undefined;
102 186
103 if (useJson || result.Type == OSDType.String) 187 if (result is OSDMap)
104 return true; 188 return JsonStoreValueType.Undefined;
105 189
106 return false; 190 if (result is OSDArray)
191 return JsonStoreValueType.Undefined;
192
193 if (result is OSDBoolean)
194 return JsonStoreValueType.Boolean;
195
196 if (result is OSDInteger)
197 return JsonStoreValueType.Integer;
198
199 if (result is OSDReal)
200 return JsonStoreValueType.Float;
201
202 if (result is OSDString)
203 return JsonStoreValueType.String;
204
205 return JsonStoreValueType.Undefined;
107 } 206 }
108 207
109 // ----------------------------------------------------------------- 208 // -----------------------------------------------------------------
@@ -111,10 +210,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
111 /// 210 ///
112 /// </summary> 211 /// </summary>
113 // ----------------------------------------------------------------- 212 // -----------------------------------------------------------------
213 public int ArrayLength(string expr)
214 {
215 Stack<string> path;
216 if (! ParsePathExpression(expr,out path))
217 return -1;
218
219 OSD result = ProcessPathExpression(ValueStore,path);
220 if (result != null && result.Type == OSDType.Array)
221 {
222 OSDArray arr = result as OSDArray;
223 return arr.Count;
224 }
225
226 return -1;
227 }
228
229 // -----------------------------------------------------------------
230 /// <summary>
231 ///
232 /// </summary>
233 // -----------------------------------------------------------------
114 public bool GetValue(string expr, out string value, bool useJson) 234 public bool GetValue(string expr, out string value, bool useJson)
115 { 235 {
116 Stack<string> path = ParsePathExpression(expr); 236 Stack<string> path;
117 OSD result = ProcessPathExpression(m_ValueStore,path); 237 if (! ParsePathExpression(expr,out path))
238 {
239 value = "";
240 return false;
241 }
242
243 OSD result = ProcessPathExpression(ValueStore,path);
118 return ConvertOutputValue(result,out value,useJson); 244 return ConvertOutputValue(result,out value,useJson);
119 } 245 }
120 246
@@ -136,7 +262,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
136 // ----------------------------------------------------------------- 262 // -----------------------------------------------------------------
137 public bool SetValue(string expr, string value, bool useJson) 263 public bool SetValue(string expr, string value, bool useJson)
138 { 264 {
139 OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value); 265 OSD ovalue;
266
267 // One note of caution... if you use an empty string in the
268 // structure it will be assumed to be a default value and will
269 // not be seialized in the json
270
271 if (useJson)
272 {
273 // There doesn't appear to be a good way to determine if the
274 // value is valid Json other than to let the parser crash
275 try
276 {
277 ovalue = OSDParser.DeserializeJson(value);
278 }
279 catch (Exception e)
280 {
281 if (value.StartsWith("'") && value.EndsWith("'"))
282 {
283 ovalue = new OSDString(value.Substring(1,value.Length - 2));
284 }
285 else
286 {
287 return false;
288 }
289 }
290 }
291 else
292 {
293 ovalue = new OSDString(value);
294 }
295
140 return SetValueFromExpression(expr,ovalue); 296 return SetValueFromExpression(expr,ovalue);
141 } 297 }
142 298
@@ -147,10 +303,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
147 // ----------------------------------------------------------------- 303 // -----------------------------------------------------------------
148 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback) 304 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback)
149 { 305 {
150 Stack<string> path = ParsePathExpression(expr); 306 Stack<string> path;
307 if (! ParsePathExpression(expr,out path))
308 return false;
309
151 string pexpr = PathExpressionToKey(path); 310 string pexpr = PathExpressionToKey(path);
152 311
153 OSD result = ProcessPathExpression(m_ValueStore,path); 312 OSD result = ProcessPathExpression(ValueStore,path);
154 if (result == null) 313 if (result == null)
155 { 314 {
156 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); 315 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
@@ -178,10 +337,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
178 // ----------------------------------------------------------------- 337 // -----------------------------------------------------------------
179 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback) 338 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback)
180 { 339 {
181 Stack<string> path = ParsePathExpression(expr); 340 Stack<string> path;
341 if (! ParsePathExpression(expr,out path))
342 return false;
343
182 string pexpr = PathExpressionToKey(path); 344 string pexpr = PathExpressionToKey(path);
183 345
184 OSD result = ProcessPathExpression(m_ValueStore,path); 346 OSD result = ProcessPathExpression(ValueStore,path);
185 if (result == null) 347 if (result == null)
186 { 348 {
187 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); 349 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
@@ -208,25 +370,30 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
208 // ----------------------------------------------------------------- 370 // -----------------------------------------------------------------
209 protected bool SetValueFromExpression(string expr, OSD ovalue) 371 protected bool SetValueFromExpression(string expr, OSD ovalue)
210 { 372 {
211 Stack<string> path = ParsePathExpression(expr); 373 Stack<string> path;
374 if (! ParsePathExpression(expr,out path))
375 return false;
376
212 if (path.Count == 0) 377 if (path.Count == 0)
213 { 378 {
214 m_ValueStore = ovalue; 379 ValueStore = ovalue;
380 StringSpace = 0;
215 return true; 381 return true;
216 } 382 }
217 383
384 // pkey will be the final element in the path, we pull it out here to make sure
385 // that the assignment works correctly
218 string pkey = path.Pop(); 386 string pkey = path.Pop();
219 string pexpr = PathExpressionToKey(path); 387 string pexpr = PathExpressionToKey(path);
220 if (pexpr != "") 388 if (pexpr != "")
221 pexpr += "."; 389 pexpr += ".";
222 390
223 OSD result = ProcessPathExpression(m_ValueStore,path); 391 OSD result = ProcessPathExpression(ValueStore,path);
224 if (result == null) 392 if (result == null)
225 return false; 393 return false;
226 394
227 Regex aPattern = new Regex("\\[([0-9]+|\\+)\\]"); 395 // Check pkey, the last element in the path, for and extract array references
228 MatchCollection amatches = aPattern.Matches(pkey,0); 396 MatchCollection amatches = m_ArrayPattern.Matches(pkey,0);
229
230 if (amatches.Count > 0) 397 if (amatches.Count > 0)
231 { 398 {
232 if (result.Type != OSDType.Array) 399 if (result.Type != OSDType.Array)
@@ -242,8 +409,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
242 { 409 {
243 string npkey = String.Format("[{0}]",amap.Count); 410 string npkey = String.Format("[{0}]",amap.Count);
244 411
245 amap.Add(ovalue); 412 if (ovalue != null)
246 InvokeNextCallback(pexpr + npkey); 413 {
414 StringSpace += ComputeSizeOf(ovalue);
415
416 amap.Add(ovalue);
417 InvokeNextCallback(pexpr + npkey);
418 }
247 return true; 419 return true;
248 } 420 }
249 421
@@ -251,9 +423,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
251 if (0 <= aval && aval < amap.Count) 423 if (0 <= aval && aval < amap.Count)
252 { 424 {
253 if (ovalue == null) 425 if (ovalue == null)
426 {
427 StringSpace -= ComputeSizeOf(amap[aval]);
254 amap.RemoveAt(aval); 428 amap.RemoveAt(aval);
429 }
255 else 430 else
256 { 431 {
432 StringSpace -= ComputeSizeOf(amap[aval]);
433 StringSpace += ComputeSizeOf(ovalue);
257 amap[aval] = ovalue; 434 amap[aval] = ovalue;
258 InvokeNextCallback(pexpr + pkey); 435 InvokeNextCallback(pexpr + pkey);
259 } 436 }
@@ -263,9 +440,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
263 return false; 440 return false;
264 } 441 }
265 442
266 Regex hPattern = new Regex("{([^}]+)}"); 443 // Check for and extract hash references
267 MatchCollection hmatches = hPattern.Matches(pkey,0); 444 MatchCollection hmatches = m_HashPattern.Matches(pkey,0);
268
269 if (hmatches.Count > 0) 445 if (hmatches.Count > 0)
270 { 446 {
271 Match match = hmatches[0]; 447 Match match = hmatches[0];
@@ -274,16 +450,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
274 450
275 if (result is OSDMap) 451 if (result is OSDMap)
276 { 452 {
453 // this is the assignment case
277 OSDMap hmap = result as OSDMap; 454 OSDMap hmap = result as OSDMap;
278 if (ovalue != null) 455 if (ovalue != null)
279 { 456 {
457 StringSpace -= ComputeSizeOf(hmap[hkey]);
458 StringSpace += ComputeSizeOf(ovalue);
459
280 hmap[hkey] = ovalue; 460 hmap[hkey] = ovalue;
281 InvokeNextCallback(pexpr + pkey); 461 InvokeNextCallback(pexpr + pkey);
462 return true;
282 } 463 }
283 else if (hmap.ContainsKey(hkey)) 464
465 // this is the remove case
466 if (hmap.ContainsKey(hkey))
467 {
468 StringSpace -= ComputeSizeOf(hmap[hkey]);
284 hmap.Remove(hkey); 469 hmap.Remove(hkey);
285 470 return true;
286 return true; 471 }
472
473 return false;
287 } 474 }
288 475
289 return false; 476 return false;
@@ -332,39 +519,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
332 /// use a stack because we process the path in inverse order later 519 /// use a stack because we process the path in inverse order later
333 /// </summary> 520 /// </summary>
334 // ----------------------------------------------------------------- 521 // -----------------------------------------------------------------
335 protected static Stack<string> ParsePathExpression(string path) 522 protected static bool ParsePathExpression(string expr, out Stack<string> path)
336 { 523 {
337 Stack<string> m_path = new Stack<string>(); 524 path = new Stack<string>();
338 525
339 // add front and rear separators 526 // add front and rear separators
340 path = "." + path + "."; 527 expr = "." + expr + ".";
341 528
342 // add separators for quoted paths 529 // add separators for quoted exprs and array references
343 Regex pass1 = new Regex("{[^}]+}"); 530 expr = m_ParsePassOne.Replace(expr,".$1.",-1,0);
344 path = pass1.Replace(path,".$0.",-1,0);
345
346 // add separators for array references
347 Regex pass2 = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
348 path = pass2.Replace(path,".$0.",-1,0);
349 531
350 // add quotes to bare identifier 532 // add quotes to bare identifier
351 Regex pass3 = new Regex("\\.([a-zA-Z]+)"); 533 expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0);
352 path = pass3.Replace(path,".{$1}",-1,0);
353 534
354 // remove extra separators 535 // remove extra separators
355 Regex pass4 = new Regex("\\.+"); 536 expr = m_ParsePassFour.Replace(expr,".",-1,0);
356 path = pass4.Replace(path,".",-1,0);
357 537
358 Regex validate = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$"); 538 // validate the results (catches extra quote characters for example)
359 if (validate.IsMatch(path)) 539 if (m_ValidatePath.IsMatch(expr))
360 { 540 {
361 Regex parser = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)"); 541 MatchCollection matches = m_PathComponent.Matches(expr,0);
362 MatchCollection matches = parser.Matches(path,0);
363 foreach (Match match in matches) 542 foreach (Match match in matches)
364 m_path.Push(match.Groups[1].Value); 543 path.Push(match.Groups[1].Value);
544
545 return true;
365 } 546 }
366 547
367 return m_path; 548 return false;
368 } 549 }
369 550
370 // ----------------------------------------------------------------- 551 // -----------------------------------------------------------------
@@ -385,9 +566,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
385 return null; 566 return null;
386 567
387 // ---------- Check for an array index ---------- 568 // ---------- Check for an array index ----------
388 Regex aPattern = new Regex("\\[([0-9]+)\\]"); 569 MatchCollection amatches = m_SimpleArrayPattern.Matches(pkey,0);
389 MatchCollection amatches = aPattern.Matches(pkey,0); 570
390
391 if (amatches.Count > 0) 571 if (amatches.Count > 0)
392 { 572 {
393 if (rmap.Type != OSDType.Array) 573 if (rmap.Type != OSDType.Array)
@@ -410,9 +590,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
410 } 590 }
411 591
412 // ---------- Check for a hash index ---------- 592 // ---------- Check for a hash index ----------
413 Regex hPattern = new Regex("{([^}]+)}"); 593 MatchCollection hmatches = m_HashPattern.Matches(pkey,0);
414 MatchCollection hmatches = hPattern.Matches(pkey,0); 594
415
416 if (hmatches.Count > 0) 595 if (hmatches.Count > 0)
417 { 596 {
418 if (rmap.Type != OSDType.Map) 597 if (rmap.Type != OSDType.Map)
@@ -456,14 +635,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
456 // The path pointed to an intermediate hash structure 635 // The path pointed to an intermediate hash structure
457 if (result.Type == OSDType.Map) 636 if (result.Type == OSDType.Map)
458 { 637 {
459 value = OSDParser.SerializeJsonString(result as OSDMap); 638 value = OSDParser.SerializeJsonString(result as OSDMap,true);
460 return true; 639 return true;
461 } 640 }
462 641
463 // The path pointed to an intermediate hash structure 642 // The path pointed to an intermediate hash structure
464 if (result.Type == OSDType.Array) 643 if (result.Type == OSDType.Array)
465 { 644 {
466 value = OSDParser.SerializeJsonString(result as OSDArray); 645 value = OSDParser.SerializeJsonString(result as OSDArray,true);
467 return true; 646 return true;
468 } 647 }
469 648
@@ -471,7 +650,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
471 return true; 650 return true;
472 } 651 }
473 652
474 if (result.Type == OSDType.String) 653 if (OSDBaseType(result.Type))
475 { 654 {
476 value = result.AsString(); 655 value = result.AsString();
477 return true; 656 return true;
@@ -496,5 +675,91 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
496 675
497 return pkey; 676 return pkey;
498 } 677 }
678
679 // -----------------------------------------------------------------
680 /// <summary>
681 ///
682 /// </summary>
683 // -----------------------------------------------------------------
684 protected static bool OSDBaseType(OSDType type)
685 {
686 // Should be the list of base types for which AsString() returns
687 // something useful
688 if (type == OSDType.Boolean)
689 return true;
690 if (type == OSDType.Integer)
691 return true;
692 if (type == OSDType.Real)
693 return true;
694 if (type == OSDType.String)
695 return true;
696 if (type == OSDType.UUID)
697 return true;
698 if (type == OSDType.Date)
699 return true;
700 if (type == OSDType.URI)
701 return true;
702
703 return false;
704 }
705
706 // -----------------------------------------------------------------
707 /// <summary>
708 ///
709 /// </summary>
710 // -----------------------------------------------------------------
711 protected static int ComputeSizeOf(OSD value)
712 {
713 string sval;
714
715 if (ConvertOutputValue(value,out sval,true))
716 return sval.Length;
717
718 return 0;
719 }
720 }
721
722 // -----------------------------------------------------------------
723 /// <summary>
724 /// </summary>
725 // -----------------------------------------------------------------
726 public class JsonObjectStore : JsonStore
727 {
728 private static readonly ILog m_log =
729 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
730
731 private Scene m_scene;
732 private UUID m_objectID;
733
734 protected override OSD ValueStore
735 {
736 get
737 {
738 SceneObjectPart sop = m_scene.GetSceneObjectPart(m_objectID);
739 if (sop == null)
740 {
741 // This is bad
742 return null;
743 }
744
745 return sop.DynAttrs.TopLevelMap;
746 }
747
748 // cannot set the top level
749 set
750 {
751 m_log.InfoFormat("[JsonStore] cannot set top level value in object store");
752 }
753 }
754
755 public JsonObjectStore(Scene scene, UUID oid) : base()
756 {
757 m_scene = scene;
758 m_objectID = oid;
759
760 // the size limit is imposed on whatever is already in the store
761 StringSpace = ComputeSizeOf(ValueStore);
762 }
499 } 763 }
764
500} 765}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
index e68764a..5fbfcc5 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -54,6 +54,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
54 54
55 private IConfig m_config = null; 55 private IConfig m_config = null;
56 private bool m_enabled = false; 56 private bool m_enabled = false;
57 private bool m_enableObjectStore = false;
58 private int m_maxStringSpace = Int32.MaxValue;
59
57 private Scene m_scene = null; 60 private Scene m_scene = null;
58 61
59 private Dictionary<UUID,JsonStore> m_JsonValueStore; 62 private Dictionary<UUID,JsonStore> m_JsonValueStore;
@@ -90,15 +93,19 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
90 } 93 }
91 94
92 m_enabled = m_config.GetBoolean("Enabled", m_enabled); 95 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
96 m_enableObjectStore = m_config.GetBoolean("EnableObjectStore", m_enableObjectStore);
97 m_maxStringSpace = m_config.GetInt("MaxStringSpace", m_maxStringSpace);
98 if (m_maxStringSpace == 0)
99 m_maxStringSpace = Int32.MaxValue;
93 } 100 }
94 catch (Exception e) 101 catch (Exception e)
95 { 102 {
96 m_log.ErrorFormat("[JsonStore] initialization error: {0}",e.Message); 103 m_log.Error("[JsonStore]: initialization error: {0}", e);
97 return; 104 return;
98 } 105 }
99 106
100 if (m_enabled) 107 if (m_enabled)
101 m_log.DebugFormat("[JsonStore] module is enabled"); 108 m_log.DebugFormat("[JsonStore]: module is enabled");
102 } 109 }
103 110
104 // ----------------------------------------------------------------- 111 // -----------------------------------------------------------------
@@ -175,6 +182,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
175 /// 182 ///
176 /// </summary> 183 /// </summary>
177 // ----------------------------------------------------------------- 184 // -----------------------------------------------------------------
185 public bool AttachObjectStore(UUID objectID)
186 {
187 if (! m_enabled) return false;
188 if (! m_enableObjectStore) return false;
189
190 SceneObjectPart sop = m_scene.GetSceneObjectPart(objectID);
191 if (sop == null)
192 {
193 m_log.ErrorFormat("[JsonStore] unable to attach to unknown object; {0}", objectID);
194 return false;
195 }
196
197 lock (m_JsonValueStore)
198 {
199 if (m_JsonValueStore.ContainsKey(objectID))
200 return true;
201
202 JsonStore map = new JsonObjectStore(m_scene,objectID);
203 m_JsonValueStore.Add(objectID,map);
204 }
205
206 return true;
207 }
208
209 // -----------------------------------------------------------------
210 /// <summary>
211 ///
212 /// </summary>
213 // -----------------------------------------------------------------
178 public bool CreateStore(string value, ref UUID result) 214 public bool CreateStore(string value, ref UUID result)
179 { 215 {
180 if (result == UUID.Zero) 216 if (result == UUID.Zero)
@@ -191,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
191 } 227 }
192 catch (Exception e) 228 catch (Exception e)
193 { 229 {
194 m_log.InfoFormat("[JsonStore] Unable to initialize store from {0}; {1}",value,e.Message); 230 m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value);
195 return false; 231 return false;
196 } 232 }
197 233
@@ -211,7 +247,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
211 if (! m_enabled) return false; 247 if (! m_enabled) return false;
212 248
213 lock (m_JsonValueStore) 249 lock (m_JsonValueStore)
214 m_JsonValueStore.Remove(storeID); 250 return m_JsonValueStore.Remove(storeID);
215 251
216 return true; 252 return true;
217 } 253 }
@@ -221,31 +257,76 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
221 /// 257 ///
222 /// </summary> 258 /// </summary>
223 // ----------------------------------------------------------------- 259 // -----------------------------------------------------------------
224 public bool TestPath(UUID storeID, string path, bool useJson) 260 public bool TestStore(UUID storeID)
225 { 261 {
226 if (! m_enabled) return false; 262 if (! m_enabled) return false;
227 263
264 lock (m_JsonValueStore)
265 return m_JsonValueStore.ContainsKey(storeID);
266 }
267
268 // -----------------------------------------------------------------
269 /// <summary>
270 ///
271 /// </summary>
272 // -----------------------------------------------------------------
273 public JsonStoreNodeType GetNodeType(UUID storeID, string path)
274 {
275 if (! m_enabled) return JsonStoreNodeType.Undefined;
276
228 JsonStore map = null; 277 JsonStore map = null;
229 lock (m_JsonValueStore) 278 lock (m_JsonValueStore)
230 { 279 {
231 if (! m_JsonValueStore.TryGetValue(storeID,out map)) 280 if (! m_JsonValueStore.TryGetValue(storeID,out map))
232 { 281 {
233 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); 282 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
234 return false; 283 return JsonStoreNodeType.Undefined;
235 } 284 }
236 } 285 }
237 286
238 try 287 try
239 { 288 {
240 lock (map) 289 lock (map)
241 return map.TestPath(path,useJson); 290 return map.GetNodeType(path);
242 } 291 }
243 catch (Exception e) 292 catch (Exception e)
244 { 293 {
245 m_log.InfoFormat("[JsonStore] Path test failed for {0} in {1}; {2}",path,storeID,e.Message); 294 m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
246 } 295 }
247 296
248 return false; 297 return JsonStoreNodeType.Undefined;
298 }
299
300 // -----------------------------------------------------------------
301 /// <summary>
302 ///
303 /// </summary>
304 // -----------------------------------------------------------------
305 public JsonStoreValueType GetValueType(UUID storeID, string path)
306 {
307 if (! m_enabled) return JsonStoreValueType.Undefined;
308
309 JsonStore map = null;
310 lock (m_JsonValueStore)
311 {
312 if (! m_JsonValueStore.TryGetValue(storeID,out map))
313 {
314 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
315 return JsonStoreValueType.Undefined;
316 }
317 }
318
319 try
320 {
321 lock (map)
322 return map.GetValueType(path);
323 }
324 catch (Exception e)
325 {
326 m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
327 }
328
329 return JsonStoreValueType.Undefined;
249 } 330 }
250 331
251 // ----------------------------------------------------------------- 332 // -----------------------------------------------------------------
@@ -270,12 +351,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
270 try 351 try
271 { 352 {
272 lock (map) 353 lock (map)
273 if (map.SetValue(path,value,useJson)) 354 {
274 return true; 355 if (map.StringSpace > m_maxStringSpace)
356 {
357 m_log.WarnFormat("[JsonStore] {0} exceeded string size; {1} bytes used of {2} limit",
358 storeID,map.StringSpace,m_maxStringSpace);
359 return false;
360 }
361
362 return map.SetValue(path,value,useJson);
363 }
275 } 364 }
276 catch (Exception e) 365 catch (Exception e)
277 { 366 {
278 m_log.InfoFormat("[JsonStore] Unable to assign {0} to {1} in {2}; {3}",value,path,storeID,e.Message); 367 m_log.Error(string.Format("[JsonStore]: Unable to assign {0} to {1} in {2}", value, path, storeID), e);
279 } 368 }
280 369
281 return false; 370 return false;
@@ -303,12 +392,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
303 try 392 try
304 { 393 {
305 lock (map) 394 lock (map)
306 if (map.RemoveValue(path)) 395 return map.RemoveValue(path);
307 return true;
308 } 396 }
309 catch (Exception e) 397 catch (Exception e)
310 { 398 {
311 m_log.InfoFormat("[JsonStore] Unable to remove {0} in {1}; {2}",path,storeID,e.Message); 399 m_log.Error(string.Format("[JsonStore]: Unable to remove {0} in {1}", path, storeID), e);
312 } 400 }
313 401
314 return false; 402 return false;
@@ -319,6 +407,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
319 /// 407 ///
320 /// </summary> 408 /// </summary>
321 // ----------------------------------------------------------------- 409 // -----------------------------------------------------------------
410 public int GetArrayLength(UUID storeID, string path)
411 {
412 if (! m_enabled) return -1;
413
414 JsonStore map = null;
415 lock (m_JsonValueStore)
416 {
417 if (! m_JsonValueStore.TryGetValue(storeID,out map))
418 return -1;
419 }
420
421 try
422 {
423 lock (map)
424 {
425 return map.ArrayLength(path);
426 }
427 }
428 catch (Exception e)
429 {
430 m_log.Error("[JsonStore]: unable to retrieve value", e);
431 }
432
433 return -1;
434 }
435
436 // -----------------------------------------------------------------
437 /// <summary>
438 ///
439 /// </summary>
440 // -----------------------------------------------------------------
322 public bool GetValue(UUID storeID, string path, bool useJson, out string value) 441 public bool GetValue(UUID storeID, string path, bool useJson, out string value)
323 { 442 {
324 value = String.Empty; 443 value = String.Empty;
@@ -341,7 +460,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
341 } 460 }
342 catch (Exception e) 461 catch (Exception e)
343 { 462 {
344 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.Message); 463 m_log.Error("[JsonStore]: unable to retrieve value", e);
345 } 464 }
346 465
347 return false; 466 return false;
@@ -380,7 +499,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
380 } 499 }
381 catch (Exception e) 500 catch (Exception e)
382 { 501 {
383 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); 502 m_log.Error("[JsonStore] unable to retrieve value", e);
384 } 503 }
385 504
386 cback(String.Empty); 505 cback(String.Empty);
@@ -419,7 +538,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
419 } 538 }
420 catch (Exception e) 539 catch (Exception e)
421 { 540 {
422 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); 541 m_log.Error("[JsonStore]: unable to retrieve value", e);
423 } 542 }
424 543
425 cback(String.Empty); 544 cback(String.Empty);
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
index 0c175ca..1bb5aee 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -39,8 +39,10 @@ using OpenMetaverse.StructuredData;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Scenes.Scripting;
42using System.Collections.Generic; 43using System.Collections.Generic;
43using System.Text.RegularExpressions; 44using System.Text.RegularExpressions;
45using PermissionMask = OpenSim.Framework.PermissionMask;
44 46
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore 47namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{ 48{
@@ -92,12 +94,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
92 } 94 }
93 catch (Exception e) 95 catch (Exception e)
94 { 96 {
95 m_log.ErrorFormat("[JsonStoreScripts] initialization error: {0}",e.Message); 97 m_log.ErrorFormat("[JsonStoreScripts]: initialization error: {0}", e.Message);
96 return; 98 return;
97 } 99 }
98 100
99 if (m_enabled) 101 if (m_enabled)
100 m_log.DebugFormat("[JsonStoreScripts] module is enabled"); 102 m_log.DebugFormat("[JsonStoreScripts]: module is enabled");
101 } 103 }
102 104
103 // ----------------------------------------------------------------- 105 // -----------------------------------------------------------------
@@ -150,7 +152,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
150 m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>(); 152 m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>();
151 if (m_comms == null) 153 if (m_comms == null)
152 { 154 {
153 m_log.ErrorFormat("[JsonStoreScripts] ScriptModuleComms interface not defined"); 155 m_log.ErrorFormat("[JsonStoreScripts]: ScriptModuleComms interface not defined");
154 m_enabled = false; 156 m_enabled = false;
155 return; 157 return;
156 } 158 }
@@ -158,40 +160,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
158 m_store = m_scene.RequestModuleInterface<IJsonStoreModule>(); 160 m_store = m_scene.RequestModuleInterface<IJsonStoreModule>();
159 if (m_store == null) 161 if (m_store == null)
160 { 162 {
161 m_log.ErrorFormat("[JsonStoreScripts] JsonModule interface not defined"); 163 m_log.ErrorFormat("[JsonStoreScripts]: JsonModule interface not defined");
162 m_enabled = false; 164 m_enabled = false;
163 return; 165 return;
164 } 166 }
165 167
166 try 168 try
167 { 169 {
168 m_comms.RegisterScriptInvocation(this,"JsonCreateStore"); 170 m_comms.RegisterScriptInvocations(this);
169 m_comms.RegisterScriptInvocation(this,"JsonDestroyStore"); 171 m_comms.RegisterConstants(this);
170
171 m_comms.RegisterScriptInvocation(this,"JsonReadNotecard");
172 m_comms.RegisterScriptInvocation(this,"JsonWriteNotecard");
173
174 m_comms.RegisterScriptInvocation(this,"JsonTestPath");
175 m_comms.RegisterScriptInvocation(this,"JsonTestPathJson");
176
177 m_comms.RegisterScriptInvocation(this,"JsonGetValue");
178 m_comms.RegisterScriptInvocation(this,"JsonGetValueJson");
179
180 m_comms.RegisterScriptInvocation(this,"JsonTakeValue");
181 m_comms.RegisterScriptInvocation(this,"JsonTakeValueJson");
182
183 m_comms.RegisterScriptInvocation(this,"JsonReadValue");
184 m_comms.RegisterScriptInvocation(this,"JsonReadValueJson");
185
186 m_comms.RegisterScriptInvocation(this,"JsonSetValue");
187 m_comms.RegisterScriptInvocation(this,"JsonSetValueJson");
188
189 m_comms.RegisterScriptInvocation(this,"JsonRemoveValue");
190 } 172 }
191 catch (Exception e) 173 catch (Exception e)
192 { 174 {
193 // See http://opensimulator.org/mantis/view.php?id=5971 for more information 175 // See http://opensimulator.org/mantis/view.php?id=5971 for more information
194 m_log.WarnFormat("[JsonStroreScripts] script method registration failed; {0}",e.Message); 176 m_log.WarnFormat("[JsonStoreScripts]: script method registration failed; {0}", e.Message);
195 m_enabled = false; 177 m_enabled = false;
196 } 178 }
197 } 179 }
@@ -208,23 +190,61 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
208 190
209#endregion 191#endregion
210 192
193#region ScriptConstantsInterface
194
195 [ScriptConstant]
196 public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
197
198 [ScriptConstant]
199 public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object;
200
201 [ScriptConstant]
202 public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array;
203
204 [ScriptConstant]
205 public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value;
206
207 [ScriptConstant]
208 public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined;
209
210 [ScriptConstant]
211 public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean;
212
213 [ScriptConstant]
214 public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer;
215
216 [ScriptConstant]
217 public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float;
218
219 [ScriptConstant]
220 public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String;
221
222
223#endregion
224
211#region ScriptInvocationInteface 225#region ScriptInvocationInteface
212 // ----------------------------------------------------------------- 226 // -----------------------------------------------------------------
213 /// <summary> 227 /// <summary>
214 /// 228 ///
215 /// </summary> 229 /// </summary>
216 // ----------------------------------------------------------------- 230 // -----------------------------------------------------------------
217 protected void GenerateRuntimeError(string msg) 231 [ScriptInvocation]
232 public UUID JsonAttachObjectStore(UUID hostID, UUID scriptID)
218 { 233 {
219 throw new Exception("JsonStore Runtime Error: " + msg); 234 UUID uuid = UUID.Zero;
235 if (! m_store.AttachObjectStore(hostID))
236 GenerateRuntimeError("Failed to create Json store");
237
238 return hostID;
220 } 239 }
221 240
222 // ----------------------------------------------------------------- 241 // -----------------------------------------------------------------
223 /// <summary> 242 /// <summary>
224 /// 243 ///
225 /// </summary> 244 /// </summary>
226 // ----------------------------------------------------------------- 245 // -----------------------------------------------------------------
227 protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) 246 [ScriptInvocation]
247 public UUID JsonCreateStore(UUID hostID, UUID scriptID, string value)
228 { 248 {
229 UUID uuid = UUID.Zero; 249 UUID uuid = UUID.Zero;
230 if (! m_store.CreateStore(value, ref uuid)) 250 if (! m_store.CreateStore(value, ref uuid))
@@ -238,7 +258,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
238 /// 258 ///
239 /// </summary> 259 /// </summary>
240 // ----------------------------------------------------------------- 260 // -----------------------------------------------------------------
241 protected int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) 261 [ScriptInvocation]
262 public int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID)
242 { 263 {
243 return m_store.DestroyStore(storeID) ? 1 : 0; 264 return m_store.DestroyStore(storeID) ? 1 : 0;
244 } 265 }
@@ -248,10 +269,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
248 /// 269 ///
249 /// </summary> 270 /// </summary>
250 // ----------------------------------------------------------------- 271 // -----------------------------------------------------------------
251 protected UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) 272 [ScriptInvocation]
273 public int JsonTestStore(UUID hostID, UUID scriptID, UUID storeID)
274 {
275 return m_store.TestStore(storeID) ? 1 : 0;
276 }
277
278 // -----------------------------------------------------------------
279 /// <summary>
280 ///
281 /// </summary>
282 // -----------------------------------------------------------------
283 [ScriptInvocation]
284 public UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier)
252 { 285 {
253 UUID reqID = UUID.Random(); 286 UUID reqID = UUID.Random();
254 Util.FireAndForget(delegate(object o) { DoJsonReadNotecard(reqID,hostID,scriptID,storeID,path,assetID); }); 287 Util.FireAndForget(o => DoJsonReadNotecard(reqID, hostID, scriptID, storeID, path, notecardIdentifier));
255 return reqID; 288 return reqID;
256 } 289 }
257 290
@@ -260,7 +293,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
260 /// 293 ///
261 /// </summary> 294 /// </summary>
262 // ----------------------------------------------------------------- 295 // -----------------------------------------------------------------
263 protected UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name) 296 [ScriptInvocation]
297 public UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name)
264 { 298 {
265 UUID reqID = UUID.Random(); 299 UUID reqID = UUID.Random();
266 Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); }); 300 Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); });
@@ -272,14 +306,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
272 /// 306 ///
273 /// </summary> 307 /// </summary>
274 // ----------------------------------------------------------------- 308 // -----------------------------------------------------------------
275 protected int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) 309 [ScriptInvocation]
310 public string JsonList2Path(UUID hostID, UUID scriptID, object[] pathlist)
276 { 311 {
277 return m_store.TestPath(storeID,path,false) ? 1 : 0; 312 string ipath = ConvertList2Path(pathlist);
313 string opath;
314
315 if (JsonStore.CanonicalPathExpression(ipath,out opath))
316 return opath;
317
318 // This won't parse if passed to the other routines as opposed to
319 // returning an empty string which is a valid path and would overwrite
320 // the entire store
321 return "**INVALID**";
322 }
323
324 // -----------------------------------------------------------------
325 /// <summary>
326 ///
327 /// </summary>
328 // -----------------------------------------------------------------
329 [ScriptInvocation]
330 public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path)
331 {
332 return (int)m_store.GetNodeType(storeID,path);
278 } 333 }
279 334
280 protected int JsonTestPathJson(UUID hostID, UUID scriptID, UUID storeID, string path) 335 // -----------------------------------------------------------------
336 /// <summary>
337 ///
338 /// </summary>
339 // -----------------------------------------------------------------
340 [ScriptInvocation]
341 public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path)
281 { 342 {
282 return m_store.TestPath(storeID,path,true) ? 1 : 0; 343 return (int)m_store.GetValueType(storeID,path);
283 } 344 }
284 345
285 // ----------------------------------------------------------------- 346 // -----------------------------------------------------------------
@@ -287,12 +348,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
287 /// 348 ///
288 /// </summary> 349 /// </summary>
289 // ----------------------------------------------------------------- 350 // -----------------------------------------------------------------
290 protected int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value) 351 [ScriptInvocation]
352 public int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
291 { 353 {
292 return m_store.SetValue(storeID,path,value,false) ? 1 : 0; 354 return m_store.SetValue(storeID,path,value,false) ? 1 : 0;
293 } 355 }
294 356
295 protected int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) 357 [ScriptInvocation]
358 public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
296 { 359 {
297 return m_store.SetValue(storeID,path,value,true) ? 1 : 0; 360 return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
298 } 361 }
@@ -302,7 +365,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
302 /// 365 ///
303 /// </summary> 366 /// </summary>
304 // ----------------------------------------------------------------- 367 // -----------------------------------------------------------------
305 protected int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path) 368 [ScriptInvocation]
369 public int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path)
306 { 370 {
307 return m_store.RemoveValue(storeID,path) ? 1 : 0; 371 return m_store.RemoveValue(storeID,path) ? 1 : 0;
308 } 372 }
@@ -312,14 +376,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
312 /// 376 ///
313 /// </summary> 377 /// </summary>
314 // ----------------------------------------------------------------- 378 // -----------------------------------------------------------------
315 protected string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) 379 [ScriptInvocation]
380 public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path)
381 {
382 return m_store.GetArrayLength(storeID,path);
383 }
384
385 // -----------------------------------------------------------------
386 /// <summary>
387 ///
388 /// </summary>
389 // -----------------------------------------------------------------
390 [ScriptInvocation]
391 public string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path)
316 { 392 {
317 string value = String.Empty; 393 string value = String.Empty;
318 m_store.GetValue(storeID,path,false,out value); 394 m_store.GetValue(storeID,path,false,out value);
319 return value; 395 return value;
320 } 396 }
321 397
322 protected string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 398 [ScriptInvocation]
399 public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path)
323 { 400 {
324 string value = String.Empty; 401 string value = String.Empty;
325 m_store.GetValue(storeID,path,true, out value); 402 m_store.GetValue(storeID,path,true, out value);
@@ -331,80 +408,105 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
331 /// 408 ///
332 /// </summary> 409 /// </summary>
333 // ----------------------------------------------------------------- 410 // -----------------------------------------------------------------
334 protected UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path) 411 [ScriptInvocation]
412 public UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path)
335 { 413 {
336 UUID reqID = UUID.Random(); 414 UUID reqID = UUID.Random();
337 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); }); 415 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); });
338 return reqID; 416 return reqID;
339 } 417 }
340 418
341 protected UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 419 [ScriptInvocation]
420 public UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
342 { 421 {
343 UUID reqID = UUID.Random(); 422 UUID reqID = UUID.Random();
344 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); }); 423 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); });
345 return reqID; 424 return reqID;
346 } 425 }
347 426
348 private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
349 {
350 try
351 {
352 m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
353 return;
354 }
355 catch (Exception e)
356 {
357 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString());
358 }
359
360 DispatchValue(scriptID,reqID,String.Empty);
361 }
362
363
364 // ----------------------------------------------------------------- 427 // -----------------------------------------------------------------
365 /// <summary> 428 /// <summary>
366 /// 429 ///
367 /// </summary> 430 /// </summary>
368 // ----------------------------------------------------------------- 431 // -----------------------------------------------------------------
369 protected UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path) 432 [ScriptInvocation]
433 public UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path)
370 { 434 {
371 UUID reqID = UUID.Random(); 435 UUID reqID = UUID.Random();
372 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); }); 436 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); });
373 return reqID; 437 return reqID;
374 } 438 }
375 439
376 protected UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 440 [ScriptInvocation]
441 public UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
377 { 442 {
378 UUID reqID = UUID.Random(); 443 UUID reqID = UUID.Random();
379 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); }); 444 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); });
380 return reqID; 445 return reqID;
381 } 446 }
382 447
383 private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) 448#endregion
449
450 // -----------------------------------------------------------------
451 /// <summary>
452 ///
453 /// </summary>
454 // -----------------------------------------------------------------
455 protected void GenerateRuntimeError(string msg)
456 {
457 m_log.InfoFormat("[JsonStore] runtime error: {0}",msg);
458 throw new Exception("JsonStore Runtime Error: " + msg);
459 }
460
461 // -----------------------------------------------------------------
462 /// <summary>
463 ///
464 /// </summary>
465 // -----------------------------------------------------------------
466 protected void DispatchValue(UUID scriptID, UUID reqID, string value)
467 {
468 m_comms.DispatchReply(scriptID,1,value,reqID.ToString());
469 }
470
471 // -----------------------------------------------------------------
472 /// <summary>
473 ///
474 /// </summary>
475 // -----------------------------------------------------------------
476 private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
384 { 477 {
385 try 478 try
386 { 479 {
387 m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); 480 m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
388 return; 481 return;
389 } 482 }
390 catch (Exception e) 483 catch (Exception e)
391 { 484 {
392 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString()); 485 m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString());
393 } 486 }
394 487
395 DispatchValue(scriptID,reqID,String.Empty); 488 DispatchValue(scriptID,reqID,String.Empty);
396 } 489 }
397 490
398#endregion
399 491
400 // ----------------------------------------------------------------- 492 // -----------------------------------------------------------------
401 /// <summary> 493 /// <summary>
402 /// 494 ///
403 /// </summary> 495 /// </summary>
404 // ----------------------------------------------------------------- 496 // -----------------------------------------------------------------
405 protected void DispatchValue(UUID scriptID, UUID reqID, string value) 497 private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
406 { 498 {
407 m_comms.DispatchReply(scriptID,1,value,reqID.ToString()); 499 try
500 {
501 m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
502 return;
503 }
504 catch (Exception e)
505 {
506 m_log.InfoFormat("[JsonStoreScripts]: unable to retrieve value; {0}",e.ToString());
507 }
508
509 DispatchValue(scriptID,reqID,String.Empty);
408 } 510 }
409 511
410 // ----------------------------------------------------------------- 512 // -----------------------------------------------------------------
@@ -412,31 +514,40 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
412 /// 514 ///
413 /// </summary> 515 /// </summary>
414 // ----------------------------------------------------------------- 516 // -----------------------------------------------------------------
415 private void DoJsonReadNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) 517 private void DoJsonReadNotecard(
518 UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, string notecardIdentifier)
416 { 519 {
520 UUID assetID;
521
522 if (!UUID.TryParse(notecardIdentifier, out assetID))
523 {
524 SceneObjectPart part = m_scene.GetSceneObjectPart(hostID);
525 assetID = ScriptUtils.GetAssetIdFromItemName(part, notecardIdentifier, (int)AssetType.Notecard);
526 }
527
417 AssetBase a = m_scene.AssetService.Get(assetID.ToString()); 528 AssetBase a = m_scene.AssetService.Get(assetID.ToString());
418 if (a == null) 529 if (a == null)
419 GenerateRuntimeError(String.Format("Unable to find notecard asset {0}",assetID)); 530 GenerateRuntimeError(String.Format("Unable to find notecard asset {0}", assetID));
420 531
421 if (a.Type != (sbyte)AssetType.Notecard) 532 if (a.Type != (sbyte)AssetType.Notecard)
422 GenerateRuntimeError(String.Format("Invalid notecard asset {0}",assetID)); 533 GenerateRuntimeError(String.Format("Invalid notecard asset {0}", assetID));
423 534
424 m_log.DebugFormat("[JsonStoreScripts] read notecard in context {0}",storeID); 535 m_log.DebugFormat("[JsonStoreScripts]: read notecard in context {0}",storeID);
425 536
426 try 537 try
427 { 538 {
428 string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); 539 string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data));
429 int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; 540 int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0;
430 m_comms.DispatchReply(scriptID,result, "", reqID.ToString()); 541 m_comms.DispatchReply(scriptID, result, "", reqID.ToString());
431 return; 542 return;
432 } 543 }
433 catch (Exception e) 544 catch (Exception e)
434 { 545 {
435 m_log.WarnFormat("[JsonStoreScripts] Json parsing failed; {0}",e.Message); 546 m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message);
436 } 547 }
437 548
438 GenerateRuntimeError(String.Format("Json parsing failed for {0}",assetID.ToString())); 549 GenerateRuntimeError(String.Format("Json parsing failed for {0}", assetID));
439 m_comms.DispatchReply(scriptID,0,"",reqID.ToString()); 550 m_comms.DispatchReply(scriptID, 0, "", reqID.ToString());
440 } 551 }
441 552
442 // ----------------------------------------------------------------- 553 // -----------------------------------------------------------------
@@ -494,5 +605,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
494 605
495 m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString()); 606 m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString());
496 } 607 }
608
609 // -----------------------------------------------------------------
610 /// <summary>
611 /// Convert a list of values that are path components to a single string path
612 /// </summary>
613 // -----------------------------------------------------------------
614 protected static Regex m_ArrayPattern = new Regex("^([0-9]+|\\+)$");
615 private string ConvertList2Path(object[] pathlist)
616 {
617 string path = "";
618 for (int i = 0; i < pathlist.Length; i++)
619 {
620 string token = "";
621
622 if (pathlist[i] is string)
623 {
624 token = pathlist[i].ToString();
625
626 // Check to see if this is a bare number which would not be a valid
627 // identifier otherwise
628 if (m_ArrayPattern.IsMatch(token))
629 token = '[' + token + ']';
630 }
631 else if (pathlist[i] is int)
632 {
633 token = "[" + pathlist[i].ToString() + "]";
634 }
635 else
636 {
637 token = "." + pathlist[i].ToString() + ".";
638 }
639
640 path += token + ".";
641 }
642
643 return path;
644 }
645
497 } 646 }
498} 647}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
new file mode 100644
index 0000000..bfa9937
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
@@ -0,0 +1,901 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using log4net;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Scripting.ScriptModuleComms;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.ScriptEngine.Shared;
40using OpenSim.Region.ScriptEngine.Shared.Api;
41using OpenSim.Services.Interfaces;
42using OpenSim.Tests.Common;
43using OpenSim.Tests.Common.Mock;
44
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
46{
47 /// <summary>
48 /// Tests for inventory functions in LSL
49 /// </summary>
50 [TestFixture]
51 public class JsonStoreScriptModuleTests : OpenSimTestCase
52 {
53 private Scene m_scene;
54 private MockScriptEngine m_engine;
55 private ScriptModuleCommsModule m_smcm;
56 private JsonStoreScriptModule m_jssm;
57
58 [TestFixtureSetUp]
59 public void FixtureInit()
60 {
61 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
62 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
63 }
64
65 [TestFixtureTearDown]
66 public void TearDown()
67 {
68 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
69 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
70 // tests really shouldn't).
71 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
72 }
73
74 [SetUp]
75 public override void SetUp()
76 {
77 base.SetUp();
78
79 IConfigSource configSource = new IniConfigSource();
80 IConfig jsonStoreConfig = configSource.AddConfig("JsonStore");
81 jsonStoreConfig.Set("Enabled", "true");
82
83 m_engine = new MockScriptEngine();
84 m_smcm = new ScriptModuleCommsModule();
85 JsonStoreModule jsm = new JsonStoreModule();
86 m_jssm = new JsonStoreScriptModule();
87
88 m_scene = new SceneHelpers().SetupScene();
89 SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm);
90
91 try
92 {
93 m_smcm.RegisterScriptInvocation(this, "DummyTestMethod");
94 }
95 catch (ArgumentException)
96 {
97 Assert.Ignore("Ignoring test since running on .NET 3.5 or earlier.");
98 }
99
100 // XXX: Unfortunately, ICommsModule currently has no way of deregistering methods.
101 }
102
103 private object InvokeOp(string name, params object[] args)
104 {
105 return InvokeOpOnHost(name, UUID.Zero, args);
106 }
107
108 private object InvokeOpOnHost(string name, UUID hostId, params object[] args)
109 {
110 return m_smcm.InvokeOperation(hostId, UUID.Zero, name, args);
111 }
112
113 [Test]
114 public void TestJsonCreateStore()
115 {
116 TestHelpers.InMethod();
117// TestHelpers.EnableLogging();
118
119 // Test blank store
120 {
121 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
122 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
123 }
124
125 // Test single element store
126 {
127 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
128 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
129 }
130
131 // Test with an integer value
132 {
133 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }");
134 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
135
136 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
137 Assert.That(value, Is.EqualTo("42.15"));
138 }
139
140 // Test with an array as the root node
141 {
142 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]");
143 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
144
145 string value = (string)InvokeOp("JsonGetValue", storeId, "[1]");
146 Assert.That(value, Is.EqualTo("two"));
147 }
148 }
149
150 [Test]
151 public void TestJsonDestroyStore()
152 {
153 TestHelpers.InMethod();
154// TestHelpers.EnableLogging();
155
156 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
157 int dsrv = (int)InvokeOp("JsonDestroyStore", storeId);
158
159 Assert.That(dsrv, Is.EqualTo(1));
160
161 int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
162 Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
163 }
164
165 [Test]
166 public void TestJsonDestroyStoreNotExists()
167 {
168 TestHelpers.InMethod();
169// TestHelpers.EnableLogging();
170
171 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
172
173 int dsrv = (int)InvokeOp("JsonDestroyStore", fakeStoreId);
174
175 Assert.That(dsrv, Is.EqualTo(0));
176 }
177
178 [Test]
179 public void TestJsonGetValue()
180 {
181 TestHelpers.InMethod();
182// TestHelpers.EnableLogging();
183
184 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
185
186 {
187 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World");
188 Assert.That(value, Is.EqualTo("Two"));
189 }
190
191 // Test get of path section instead of leaf
192 {
193 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
194 Assert.That(value, Is.EqualTo(""));
195 }
196
197 // Test get of non-existing value
198 {
199 string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo");
200 Assert.That(fakeValueGet, Is.EqualTo(""));
201 }
202
203 // Test get from non-existing store
204 {
205 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
206 string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
207 Assert.That(fakeStoreValueGet, Is.EqualTo(""));
208 }
209 }
210
211 [Test]
212 public void TestJsonGetJson()
213 {
214 TestHelpers.InMethod();
215// TestHelpers.EnableLogging();
216
217 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
218
219 {
220 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World");
221 Assert.That(value, Is.EqualTo("'Two'"));
222 }
223
224 // Test get of path section instead of leaf
225 {
226 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello");
227 Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}"));
228 }
229
230 // Test get of non-existing value
231 {
232 string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo");
233 Assert.That(fakeValueGet, Is.EqualTo(""));
234 }
235
236 // Test get from non-existing store
237 {
238 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
239 string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello");
240 Assert.That(fakeStoreValueGet, Is.EqualTo(""));
241 }
242 }
243
244// [Test]
245// public void TestJsonTakeValue()
246// {
247// TestHelpers.InMethod();
248//// TestHelpers.EnableLogging();
249//
250// UUID storeId
251// = (UUID)m_smcm.InvokeOperation(
252// UUID.Zero, UUID.Zero, "JsonCreateStore", new object[] { "{ 'Hello' : 'World' }" });
253//
254// string value
255// = (string)m_smcm.InvokeOperation(
256// UUID.Zero, UUID.Zero, "JsonTakeValue", new object[] { storeId, "Hello" });
257//
258// Assert.That(value, Is.EqualTo("World"));
259//
260// string value2
261// = (string)m_smcm.InvokeOperation(
262// UUID.Zero, UUID.Zero, "JsonGetValue", new object[] { storeId, "Hello" });
263//
264// Assert.That(value, Is.Null);
265// }
266
267 [Test]
268 public void TestJsonRemoveValue()
269 {
270 TestHelpers.InMethod();
271// TestHelpers.EnableLogging();
272
273 // Test remove of node in object pointing to a string
274 {
275 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
276
277 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
278 Assert.That(returnValue, Is.EqualTo(1));
279
280 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
281 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
282
283 string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
284 Assert.That(returnValue2, Is.EqualTo(""));
285 }
286
287 // Test remove of node in object pointing to another object
288 {
289 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }");
290
291 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
292 Assert.That(returnValue, Is.EqualTo(1));
293
294 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
295 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
296
297 string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
298 Assert.That(returnValue2, Is.EqualTo(""));
299 }
300
301 // Test remove of node in an array
302 {
303 UUID storeId
304 = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }");
305
306 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
307 Assert.That(returnValue, Is.EqualTo(1));
308
309 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]");
310 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
311
312 result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]");
313 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
314
315 string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
316 Assert.That(stringReturnValue, Is.EqualTo("value2"));
317
318 stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]");
319 Assert.That(stringReturnValue, Is.EqualTo(""));
320 }
321
322 // Test remove of non-existing value
323 {
324 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
325
326 int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese");
327 Assert.That(fakeValueRemove, Is.EqualTo(0));
328 }
329
330 {
331 // Test get from non-existing store
332 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
333 int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
334 Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
335 }
336 }
337
338// [Test]
339// public void TestJsonTestPath()
340// {
341// TestHelpers.InMethod();
342//// TestHelpers.EnableLogging();
343//
344// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
345//
346// {
347// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World");
348// Assert.That(result, Is.EqualTo(1));
349// }
350//
351// // Test for path which does not resolve to a value.
352// {
353// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
354// Assert.That(result, Is.EqualTo(0));
355// }
356//
357// {
358// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
359// Assert.That(result2, Is.EqualTo(0));
360// }
361//
362// // Test with fake store
363// {
364// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
365// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
366// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
367// }
368// }
369
370// [Test]
371// public void TestJsonTestPathJson()
372// {
373// TestHelpers.InMethod();
374//// TestHelpers.EnableLogging();
375//
376// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
377//
378// {
379// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World");
380// Assert.That(result, Is.EqualTo(1));
381// }
382//
383// // Test for path which does not resolve to a value.
384// {
385// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello");
386// Assert.That(result, Is.EqualTo(1));
387// }
388//
389// {
390// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo");
391// Assert.That(result2, Is.EqualTo(0));
392// }
393//
394// // Test with fake store
395// {
396// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
397// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello");
398// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
399// }
400// }
401
402 [Test]
403 public void TestJsonGetArrayLength()
404 {
405 TestHelpers.InMethod();
406// TestHelpers.EnableLogging();
407
408 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
409
410 {
411 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World");
412 Assert.That(result, Is.EqualTo(2));
413 }
414
415 // Test path which is not an array
416 {
417 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello");
418 Assert.That(result, Is.EqualTo(-1));
419 }
420
421 // Test fake path
422 {
423 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo");
424 Assert.That(result, Is.EqualTo(-1));
425 }
426
427 // Test fake store
428 {
429 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
430 int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World");
431 Assert.That(result, Is.EqualTo(-1));
432 }
433 }
434
435 [Test]
436 public void TestJsonGetNodeType()
437 {
438 TestHelpers.InMethod();
439// TestHelpers.EnableLogging();
440
441 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
442
443 {
444 int result = (int)InvokeOp("JsonGetNodeType", storeId, ".");
445 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
446 }
447
448 {
449 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
450 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
451 }
452
453 {
454 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World");
455 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY));
456 }
457
458 {
459 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]");
460 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
461 }
462
463 {
464 int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]");
465 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
466 }
467
468 // Test for non-existant path
469 {
470 int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo");
471 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
472 }
473
474 // Test for non-existant store
475 {
476 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
477 int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, ".");
478 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
479 }
480 }
481
482 [Test]
483 public void TestJsonList2Path()
484 {
485 TestHelpers.InMethod();
486// TestHelpers.EnableLogging();
487
488 // Invoking these methods directly since I just couldn't get comms module invocation to work for some reason
489 // - some confusion with the methods that take a params object[] invocation.
490 {
491 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" });
492 Assert.That(result, Is.EqualTo("{foo}"));
493 }
494
495 {
496 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" });
497 Assert.That(result, Is.EqualTo("{foo}.{bar}"));
498 }
499
500 {
501 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" });
502 Assert.That(result, Is.EqualTo("{foo}.[1].{bar}"));
503 }
504 }
505
506 [Test]
507 public void TestJsonSetValue()
508 {
509 TestHelpers.InMethod();
510// TestHelpers.EnableLogging();
511
512 {
513 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
514
515 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
516 Assert.That(result, Is.EqualTo(1));
517
518 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
519 Assert.That(value, Is.EqualTo("Times"));
520 }
521
522 // Test setting a key containing periods with delineation
523 {
524 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
525
526 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times");
527 Assert.That(result, Is.EqualTo(1));
528
529 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}");
530 Assert.That(value, Is.EqualTo("Times"));
531 }
532
533 // *** Test [] ***
534
535 // Test setting a key containing unbalanced ] without delineation. Expecting failure
536 {
537 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
538
539 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times");
540 Assert.That(result, Is.EqualTo(0));
541
542 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus");
543 Assert.That(value, Is.EqualTo(""));
544 }
545
546 // Test setting a key containing unbalanced [ without delineation. Expecting failure
547 {
548 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
549
550 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times");
551 Assert.That(result, Is.EqualTo(0));
552
553 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus");
554 Assert.That(value, Is.EqualTo(""));
555 }
556
557 // Test setting a key containing unbalanced [] without delineation. Expecting failure
558 {
559 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
560
561 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times");
562 Assert.That(result, Is.EqualTo(0));
563
564 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus");
565 Assert.That(value, Is.EqualTo(""));
566 }
567
568 // Test setting a key containing unbalanced ] with delineation
569 {
570 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
571
572 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times");
573 Assert.That(result, Is.EqualTo(1));
574
575 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}");
576 Assert.That(value, Is.EqualTo("Times"));
577 }
578
579 // Test setting a key containing unbalanced [ with delineation
580 {
581 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
582
583 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times");
584 Assert.That(result, Is.EqualTo(1));
585
586 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}");
587 Assert.That(value, Is.EqualTo("Times"));
588 }
589
590 // Test setting a key containing empty balanced [] with delineation
591 {
592 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
593
594 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times");
595 Assert.That(result, Is.EqualTo(1));
596
597 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}");
598 Assert.That(value, Is.EqualTo("Times"));
599 }
600
601// // Commented out as this currently unexpectedly fails.
602// // Test setting a key containing brackets around an integer with delineation
603// {
604// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
605//
606// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times");
607// Assert.That(result, Is.EqualTo(1));
608//
609// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}");
610// Assert.That(value, Is.EqualTo("Times"));
611// }
612
613 // *** Test {} ***
614
615 // Test setting a key containing unbalanced } without delineation. Expecting failure (?)
616 {
617 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
618
619 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times");
620 Assert.That(result, Is.EqualTo(0));
621
622 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
623 Assert.That(value, Is.EqualTo(""));
624 }
625
626 // Test setting a key containing unbalanced { without delineation. Expecting failure (?)
627 {
628 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
629
630 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times");
631 Assert.That(result, Is.EqualTo(0));
632
633 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
634 Assert.That(value, Is.EqualTo(""));
635 }
636
637// // Commented out as this currently unexpectedly fails.
638// // Test setting a key containing unbalanced }
639// {
640// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
641//
642// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times");
643// Assert.That(result, Is.EqualTo(0));
644// }
645
646 // Test setting a key containing unbalanced { with delineation
647 {
648 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
649
650 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times");
651 Assert.That(result, Is.EqualTo(1));
652
653 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}");
654 Assert.That(value, Is.EqualTo("Times"));
655 }
656
657 // Test setting a key containing balanced {} with delineation. This should fail.
658 {
659 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
660
661 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times");
662 Assert.That(result, Is.EqualTo(0));
663
664 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}");
665 Assert.That(value, Is.EqualTo(""));
666 }
667
668 // Test setting to location that does not exist. This should fail.
669 {
670 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
671
672 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times");
673 Assert.That(result, Is.EqualTo(0));
674
675 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
676 Assert.That(value, Is.EqualTo(""));
677 }
678
679 // Test with fake store
680 {
681 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
682 int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World");
683 Assert.That(fakeStoreValueSet, Is.EqualTo(0));
684 }
685 }
686
687 [Test]
688 public void TestJsonSetJson()
689 {
690 TestHelpers.InMethod();
691// TestHelpers.EnableLogging();
692
693 // Single quoted token case
694 {
695 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
696
697 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'");
698 Assert.That(result, Is.EqualTo(1));
699
700 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
701 Assert.That(value, Is.EqualTo("Times"));
702 }
703
704 // Sub-tree case
705 {
706 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
707
708 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }");
709 Assert.That(result, Is.EqualTo(1));
710
711 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled");
712 Assert.That(value, Is.EqualTo("Times"));
713 }
714
715 // If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings.
716 {
717 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
718
719 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times");
720 Assert.That(result, Is.EqualTo(0));
721
722 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
723 Assert.That(value, Is.EqualTo(""));
724 }
725
726 // Test setting to location that does not exist. This should fail.
727 {
728 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
729
730 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'");
731 Assert.That(result, Is.EqualTo(0));
732
733 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
734 Assert.That(value, Is.EqualTo(""));
735 }
736
737 // Test with fake store
738 {
739 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
740 int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'");
741 Assert.That(fakeStoreValueSet, Is.EqualTo(0));
742 }
743 }
744
745 /// <summary>
746 /// Test for writing json to a notecard
747 /// </summary>
748 /// <remarks>
749 /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
750 /// it via the MockScriptEngine or perhaps by a dummy script instance.
751 /// </remarks>
752 [Test]
753 public void TestJsonWriteNotecard()
754 {
755 TestHelpers.InMethod();
756// TestHelpers.EnableLogging();
757
758 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
759 m_scene.AddSceneObject(so);
760
761 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
762
763 {
764 string notecardName = "nc1";
765
766 // Write notecard
767 UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName);
768 Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
769
770 TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName);
771 Assert.That(nc1Item, Is.Not.Null);
772
773 // TODO: Should independently check the contents.
774 }
775
776 // TODO: Write partial test
777
778 {
779 // Try to write notecard for a bad path
780 // In this case we do get a request id but no notecard is written.
781 string badPathNotecardName = "badPathNotecardName";
782
783 UUID writeNotecardBadPathRequestId
784 = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "flibble", badPathNotecardName);
785 Assert.That(writeNotecardBadPathRequestId, Is.Not.EqualTo(UUID.Zero));
786
787 TaskInventoryItem badPathItem = so.RootPart.Inventory.GetInventoryItem(badPathNotecardName);
788 Assert.That(badPathItem, Is.Null);
789 }
790
791 {
792 // Test with fake store
793 // In this case we do get a request id but no notecard is written.
794 string fakeStoreNotecardName = "fakeStoreNotecardName";
795
796 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
797 UUID fakeStoreWriteNotecardValue
798 = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName);
799 Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero));
800
801 TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName);
802 Assert.That(fakeStoreItem, Is.Null);
803 }
804 }
805
806 /// <summary>
807 /// Test for reading json from a notecard
808 /// </summary>
809 /// <remarks>
810 /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
811 /// it via the MockScriptEngine or perhaps by a dummy script instance.
812 /// </remarks>
813 [Test]
814 public void TestJsonReadNotecard()
815 {
816 TestHelpers.InMethod();
817// TestHelpers.EnableLogging();
818
819 string notecardName = "nc1";
820
821 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
822 m_scene.AddSceneObject(so);
823
824 UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
825
826 // Write notecard
827 InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName);
828
829 {
830 // Read notecard
831 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
832 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName);
833 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
834
835 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
836 Assert.That(value, Is.EqualTo("World"));
837 }
838
839 {
840 // Read notecard to new single component path
841 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
842 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName);
843 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
844
845 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
846 Assert.That(value, Is.EqualTo(""));
847
848 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello");
849 Assert.That(value, Is.EqualTo("World"));
850 }
851
852 {
853 // Read notecard to new multi-component path. This should not work.
854 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
855 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
856 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
857
858 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
859 Assert.That(value, Is.EqualTo(""));
860
861 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
862 Assert.That(value, Is.EqualTo(""));
863 }
864
865 {
866 // Read notecard to existing multi-component path. This should work
867 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
868 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
869 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
870
871 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
872 Assert.That(value, Is.EqualTo(""));
873
874 value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
875 Assert.That(value, Is.EqualTo("World"));
876 }
877
878 {
879 // Read notecard to invalid path. This should not work.
880 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
881 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName);
882 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
883
884 string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
885 Assert.That(value, Is.EqualTo(""));
886 }
887
888 {
889 // Try read notecard to fake store.
890 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
891 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName);
892 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
893
894 string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
895 Assert.That(value, Is.EqualTo(""));
896 }
897 }
898
899 public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; }
900 }
901} \ No newline at end of file
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/ViewerSupport/DynamicFloaterModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs
new file mode 100644
index 0000000..7919fef
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs
@@ -0,0 +1,228 @@
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.IO;
30using System.Reflection;
31using System.Text;
32using System.Collections.Generic;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim;
36using OpenSim.Region;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using Nini.Config;
44using log4net;
45using Mono.Addins;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47using OSDMap = OpenMetaverse.StructuredData.OSDMap;
48
49namespace OpenSim.Region.OptionalModules.ViewerSupport
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicFloater")]
52 public class DynamicFloaterModule : INonSharedRegionModule, IDynamicFloaterModule
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57
58 private Dictionary<UUID, Dictionary<int, FloaterData>> m_floaters = new Dictionary<UUID, Dictionary<int, FloaterData>>();
59
60 public string Name
61 {
62 get { return "DynamicFloaterModule"; }
63 }
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource config)
71 {
72 }
73
74 public void Close()
75 {
76 }
77
78 public void AddRegion(Scene scene)
79 {
80 m_scene = scene;
81 scene.EventManager.OnNewClient += OnNewClient;
82 scene.EventManager.OnClientClosed += OnClientClosed;
83 m_scene.RegisterModuleInterface<IDynamicFloaterModule>(this);
84 }
85
86 public void RegionLoaded(Scene scene)
87 {
88 }
89
90 public void RemoveRegion(Scene scene)
91 {
92 }
93
94 private void OnNewClient(IClientAPI client)
95 {
96 client.OnChatFromClient += OnChatFromClient;
97 }
98
99 private void OnClientClosed(UUID agentID, Scene scene)
100 {
101 m_floaters.Remove(agentID);
102 }
103
104 private void SendToClient(ScenePresence sp, string msg)
105 {
106 sp.ControllingClient.SendChatMessage(msg,
107 (byte)ChatTypeEnum.Owner,
108 sp.AbsolutePosition,
109 "Server",
110 UUID.Zero,
111 UUID.Zero,
112 (byte)ChatSourceType.Object,
113 (byte)ChatAudibleLevel.Fully);
114 }
115
116 public void DoUserFloater(UUID agentID, FloaterData dialogData, string configuration)
117 {
118 ScenePresence sp = m_scene.GetScenePresence(agentID);
119 if (sp == null || sp.IsChildAgent)
120 return;
121
122 if (!m_floaters.ContainsKey(agentID))
123 m_floaters[agentID] = new Dictionary<int, FloaterData>();
124
125 m_floaters[agentID].Add(dialogData.Channel, dialogData);
126
127 string xml;
128 using (FileStream fs = File.Open(dialogData.XmlName + ".xml", FileMode.Open))
129 {
130 using (StreamReader sr = new StreamReader(fs))
131 xml = sr.ReadToEnd().Replace("\n", "");
132 }
133
134 List<string> xparts = new List<string>();
135
136 while (xml.Length > 0)
137 {
138 string x = xml;
139 if (x.Length > 600)
140 {
141 x = x.Substring(0, 600);
142 xml = xml.Substring(600);
143 }
144 else
145 {
146 xml = String.Empty;
147 }
148
149 xparts.Add(x);
150 }
151
152 for (int i = 0 ; i < xparts.Count ; i++)
153 SendToClient(sp, String.Format("># floater {2} create {0}/{1} " + xparts[i], i + 1, xparts.Count, dialogData.FloaterName));
154
155 SendToClient(sp, String.Format("># floater {0} {{notify:1}} {{channel: {1}}} {{node:cancel {{notify:1}}}} {{node:ok {{notify:1}}}} {2}", dialogData.FloaterName, (uint)dialogData.Channel, configuration));
156 }
157
158 private void OnChatFromClient(object sender, OSChatMessage msg)
159 {
160 if (msg.Sender == null)
161 return;
162
163 //m_log.DebugFormat("chan {0} msg {1}", msg.Channel, msg.Message);
164
165 IClientAPI client = msg.Sender;
166
167 if (!m_floaters.ContainsKey(client.AgentId))
168 return;
169
170 string[] parts = msg.Message.Split(new char[] {':'});
171 if (parts.Length == 0)
172 return;
173
174 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
175 if (sp == null || sp.IsChildAgent)
176 return;
177
178 Dictionary<int, FloaterData> d = m_floaters[client.AgentId];
179
180 // Work around a viewer bug - VALUE from any
181 // dialog can appear on this channel and needs to
182 // be dispatched to ALL open dialogs for the user
183 if (msg.Channel == 427169570)
184 {
185 if (parts[0] == "VALUE")
186 {
187 foreach (FloaterData dd in d.Values)
188 {
189 if(dd.Handler(client, dd, parts))
190 {
191 m_floaters[client.AgentId].Remove(dd.Channel);
192 SendToClient(sp, String.Format("># floater {0} destroy", dd.FloaterName));
193 break;
194 }
195 }
196 }
197 return;
198 }
199
200 if (!d.ContainsKey(msg.Channel))
201 return;
202
203 FloaterData data = d[msg.Channel];
204
205 if (parts[0] == "NOTIFY")
206 {
207 if (parts[1] == "cancel" || parts[1] == data.FloaterName)
208 {
209 m_floaters[client.AgentId].Remove(data.Channel);
210 SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName));
211 }
212 }
213
214 if (data.Handler(client, data, parts))
215 {
216 m_floaters[client.AgentId].Remove(data.Channel);
217 SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName));
218 }
219 }
220
221 public void FloaterControl(ScenePresence sp, FloaterData d, string msg)
222 {
223 string sendData = String.Format("># floater {0} {1}", d.FloaterName, msg);
224 SendToClient(sp, sendData);
225
226 }
227 }
228}
diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs
new file mode 100644
index 0000000..917911f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs
@@ -0,0 +1,282 @@
1// ******************************************************************
2// Copyright (c) 2008, 2009 Melanie Thielker
3//
4// All rights reserved
5//
6
7using System;
8using System.IO;
9using System.Reflection;
10using System.Text;
11using System.Collections.Generic;
12using OpenMetaverse;
13using OpenMetaverse.StructuredData;
14using OpenSim;
15using OpenSim.Region;
16using OpenSim.Region.Framework;
17using OpenSim.Region.Framework.Scenes;
18using OpenSim.Region.Framework.Interfaces;
19using OpenSim.Framework;
20//using OpenSim.Framework.Capabilities;
21using OpenSim.Framework.Servers;
22using OpenSim.Framework.Servers.HttpServer;
23using Nini.Config;
24using log4net;
25using Mono.Addins;
26using Caps = OpenSim.Framework.Capabilities.Caps;
27using OSDMap = OpenMetaverse.StructuredData.OSDMap;
28
29namespace OpenSim.Region.OptionalModules.ViewerSupport
30{
31 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicMenu")]
32 public class DynamicMenuModule : INonSharedRegionModule, IDynamicMenuModule
33 {
34 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
35
36 private class MenuItemData
37 {
38 public string Title;
39 public UUID AgentID;
40 public InsertLocation Location;
41 public UserMode Mode;
42 public CustomMenuHandler Handler;
43 }
44
45 private Dictionary<UUID, List<MenuItemData>> m_menuItems =
46 new Dictionary<UUID, List<MenuItemData>>();
47
48 private Scene m_scene;
49
50 public string Name
51 {
52 get { return "DynamicMenuModule"; }
53 }
54
55 public Type ReplaceableInterface
56 {
57 get { return null; }
58 }
59
60 public void Initialise(IConfigSource config)
61 {
62 }
63
64 public void Close()
65 {
66 }
67
68 public void AddRegion(Scene scene)
69 {
70 m_scene = scene;
71 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
72 m_scene.RegisterModuleInterface<IDynamicMenuModule>(this);
73 }
74
75 public void RegionLoaded(Scene scene)
76 {
77 ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>();
78
79 if (featuresModule != null)
80 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
81 }
82
83 public void RemoveRegion(Scene scene)
84 {
85 }
86
87 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
88 {
89 OSD menus = new OSDMap();
90 if (features.ContainsKey("menus"))
91 menus = features["menus"];
92
93 OSDMap agent = new OSDMap();
94 OSDMap world = new OSDMap();
95 OSDMap tools = new OSDMap();
96 OSDMap advanced = new OSDMap();
97 OSDMap admin = new OSDMap();
98 if (((OSDMap)menus).ContainsKey("agent"))
99 agent = (OSDMap)((OSDMap)menus)["agent"];
100 if (((OSDMap)menus).ContainsKey("world"))
101 world = (OSDMap)((OSDMap)menus)["world"];
102 if (((OSDMap)menus).ContainsKey("tools"))
103 tools = (OSDMap)((OSDMap)menus)["tools"];
104 if (((OSDMap)menus).ContainsKey("advanced"))
105 advanced = (OSDMap)((OSDMap)menus)["advanced"];
106 if (((OSDMap)menus).ContainsKey("admin"))
107 admin = (OSDMap)((OSDMap)menus)["admin"];
108
109 if (m_menuItems.ContainsKey(UUID.Zero))
110 {
111 foreach (MenuItemData d in m_menuItems[UUID.Zero])
112 {
113 if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID)))
114 continue;
115
116 OSDMap loc = null;
117 switch (d.Location)
118 {
119 case InsertLocation.Agent:
120 loc = agent;
121 break;
122 case InsertLocation.World:
123 loc = world;
124 break;
125 case InsertLocation.Tools:
126 loc = tools;
127 break;
128 case InsertLocation.Advanced:
129 loc = advanced;
130 break;
131 case InsertLocation.Admin:
132 loc = admin;
133 break;
134 }
135
136 if (loc == null)
137 continue;
138
139 loc[d.Title] = OSD.FromString(d.Title);
140 }
141 }
142
143 if (m_menuItems.ContainsKey(agentID))
144 {
145 foreach (MenuItemData d in m_menuItems[agentID])
146 {
147 if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID)))
148 continue;
149
150 OSDMap loc = null;
151 switch (d.Location)
152 {
153 case InsertLocation.Agent:
154 loc = agent;
155 break;
156 case InsertLocation.World:
157 loc = world;
158 break;
159 case InsertLocation.Tools:
160 loc = tools;
161 break;
162 case InsertLocation.Advanced:
163 loc = advanced;
164 break;
165 case InsertLocation.Admin:
166 loc = admin;
167 break;
168 }
169
170 if (loc == null)
171 continue;
172
173 loc[d.Title] = OSD.FromString(d.Title);
174 }
175 }
176
177
178 ((OSDMap)menus)["agent"] = agent;
179 ((OSDMap)menus)["world"] = world;
180 ((OSDMap)menus)["tools"] = tools;
181 ((OSDMap)menus)["advanced"] = advanced;
182 ((OSDMap)menus)["admin"] = admin;
183
184 features["menus"] = menus;
185 }
186
187 private void OnRegisterCaps(UUID agentID, Caps caps)
188 {
189 string capUrl = "/CAPS/" + UUID.Random() + "/";
190
191 capUrl = "/CAPS/" + UUID.Random() + "/";
192 caps.RegisterHandler("CustomMenuAction", new MenuActionHandler(capUrl, "CustomMenuAction", agentID, this, m_scene));
193 }
194
195 internal void HandleMenuSelection(string action, UUID agentID, List<uint> selection)
196 {
197 if (m_menuItems.ContainsKey(agentID))
198 {
199 foreach (MenuItemData d in m_menuItems[agentID])
200 {
201 if (d.Title == action)
202 d.Handler(action, agentID, selection);
203 }
204 }
205
206 if (m_menuItems.ContainsKey(UUID.Zero))
207 {
208 foreach (MenuItemData d in m_menuItems[UUID.Zero])
209 {
210 if (d.Title == action)
211 d.Handler(action, agentID, selection);
212 }
213 }
214 }
215
216 public void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler)
217 {
218 AddMenuItem(UUID.Zero, title, location, mode, handler);
219 }
220
221 public void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler)
222 {
223 if (!m_menuItems.ContainsKey(agentID))
224 m_menuItems[agentID] = new List<MenuItemData>();
225
226 m_menuItems[agentID].Add(new MenuItemData() { Title = title, AgentID = agentID, Location = location, Mode = mode, Handler = handler });
227 }
228
229 public void RemoveMenuItem(string action)
230 {
231 foreach (KeyValuePair<UUID,List< MenuItemData>> kvp in m_menuItems)
232 {
233 List<MenuItemData> pendingDeletes = new List<MenuItemData>();
234 foreach (MenuItemData d in kvp.Value)
235 {
236 if (d.Title == action)
237 pendingDeletes.Add(d);
238 }
239
240 foreach (MenuItemData d in pendingDeletes)
241 kvp.Value.Remove(d);
242 }
243 }
244 }
245
246 public class MenuActionHandler : BaseStreamHandler
247 {
248 private static readonly ILog m_log =
249 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
250
251 private UUID m_agentID;
252 private Scene m_scene;
253 private DynamicMenuModule m_module;
254
255 public MenuActionHandler(string path, string name, UUID agentID, DynamicMenuModule module, Scene scene)
256 :base("POST", path, name, agentID.ToString())
257 {
258 m_agentID = agentID;
259 m_scene = scene;
260 m_module = module;
261 }
262
263 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
264 {
265 StreamReader reader = new StreamReader(request);
266 string requestBody = reader.ReadToEnd();
267
268 OSD osd = OSDParser.DeserializeLLSDXml(requestBody);
269
270 string action = ((OSDMap)osd)["action"].AsString();
271 OSDArray selection = (OSDArray)((OSDMap)osd)["selection"];
272 List<uint> sel = new List<uint>();
273 for (int i = 0 ; i < selection.Count ; i++)
274 sel.Add(selection[i].AsUInteger());
275
276 Util.FireAndForget(x => { m_module.HandleMenuSelection(action, m_agentID, sel); });
277
278 Encoding encoding = Encoding.UTF8;
279 return encoding.GetBytes(OSDParser.SerializeLLSDXmlString(new OSD()));
280 }
281 }
282}
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index c7e3a7a..be020e4 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
@@ -686,19 +688,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
686 /// Event called Economy Data Request handler. 688 /// Event called Economy Data Request handler.
687 /// </summary> 689 /// </summary>
688 /// <param name="agentId"></param> 690 /// <param name="agentId"></param>
689 public void EconomyDataRequestHandler(UUID agentId) 691 public void EconomyDataRequestHandler(IClientAPI user)
690 { 692 {
691 IClientAPI user = LocateClientObject(agentId); 693 Scene s = LocateSceneClientIn(user.AgentId);
692 694
693 if (user != null) 695 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
694 { 696 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
695 Scene s = LocateSceneClientIn(user.AgentId); 697 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
696 698 TeleportMinPrice, TeleportPriceExponent);
697 user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
698 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
699 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
700 TeleportMinPrice, TeleportPriceExponent);
701 }
702 } 699 }
703 700
704 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) 701 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index d665126..7918c22 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -630,12 +630,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
630 630
631 } 631 }
632 632
633 public void SendGenericMessage(string method, List<string> message) 633 public void SendGenericMessage(string method, UUID invoice, List<string> message)
634 { 634 {
635 635
636 } 636 }
637 637
638 public void SendGenericMessage(string method, List<byte[]> message) 638 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
639 { 639 {
640 640
641 } 641 }
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index ef4005b..34362af 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;
@@ -74,6 +74,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
74 [SetUp] 74 [SetUp]
75 public void Init() 75 public void Init()
76 { 76 {
77 base.SetUp();
78
77 IConfigSource config = new IniConfigSource(); 79 IConfigSource config = new IniConfigSource();
78 config.AddConfig("NPC"); 80 config.AddConfig("NPC");
79 config.Configs["NPC"].Set("Enabled", "true"); 81 config.Configs["NPC"].Set("Enabled", "true");
diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
new file mode 100644
index 0000000..29b39e0
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
@@ -0,0 +1,266 @@
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 animations is true then extra animations debug information is logged.\n"
98 + "If collisions is false then collisions with other objects are turned off.\n"
99 + "If pbackup is false then periodic scene backup is turned off.\n"
100 + "If physics is false then all physics objects are non-physical.\n"
101 + "If scripting is false then no scripting operations happen.\n"
102 + "If teleport is true then some extra teleport debug information is logged.\n"
103 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
104 HandleDebugSceneGetCommand);
105
106 scene.AddCommand(
107 "Debug", this, "debug scene set",
108 "debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false",
109 "Turn on scene debugging options.",
110 "If active is false then main scene update and maintenance loops are suspended.\n"
111 + "If animations is true then extra animations debug information is logged.\n"
112 + "If collisions is false then collisions with other objects are turned off.\n"
113 + "If pbackup is false then periodic scene backup is turned off.\n"
114 + "If physics is false then all physics objects are non-physical.\n"
115 + "If scripting is false then no scripting operations happen.\n"
116 + "If teleport is true then some extra teleport debug information is logged.\n"
117 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
118 HandleDebugSceneSetCommand);
119
120 scene.AddCommand(
121 "Regions",
122 this, "show borders", "show borders", "Show border information for regions", HandleShowBordersCommand);
123 }
124
125 private void HandleShowBordersCommand(string module, string[] args)
126 {
127 StringBuilder sb = new StringBuilder();
128 sb.AppendFormat("Borders for {0}:\n", m_scene.Name);
129
130 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
131 cdt.AddColumn("Cross Direction", 15);
132 cdt.AddColumn("Line", 34);
133 cdt.AddColumn("Trigger Region", 14);
134
135 foreach (Border b in m_scene.NorthBorders)
136 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
137
138 foreach (Border b in m_scene.EastBorders)
139 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
140
141 foreach (Border b in m_scene.SouthBorders)
142 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
143
144 foreach (Border b in m_scene.WestBorders)
145 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
146
147 cdt.AddToStringBuilder(sb);
148
149 MainConsole.Instance.Output(sb.ToString());
150 }
151
152 private void HandleDebugSceneGetCommand(string module, string[] args)
153 {
154 if (args.Length == 3)
155 {
156 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
157 return;
158
159 OutputSceneDebugOptions();
160 }
161 else
162 {
163 MainConsole.Instance.Output("Usage: debug scene get");
164 }
165 }
166
167 private void OutputSceneDebugOptions()
168 {
169 ConsoleDisplayList cdl = new ConsoleDisplayList();
170 cdl.AddRow("active", m_scene.Active);
171 cdl.AddRow("animations", m_scene.DebugAnimations);
172 cdl.AddRow("pbackup", m_scene.PeriodicBackup);
173 cdl.AddRow("physics", m_scene.PhysicsEnabled);
174 cdl.AddRow("scripting", m_scene.ScriptsEnabled);
175 cdl.AddRow("teleport", m_scene.DebugTeleporting);
176 cdl.AddRow("updates", m_scene.DebugUpdates);
177
178 MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name);
179 MainConsole.Instance.Output(cdl.ToString());
180 }
181
182 private void HandleDebugSceneSetCommand(string module, string[] args)
183 {
184 if (args.Length == 5)
185 {
186 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
187 return;
188
189 string key = args[3];
190 string value = args[4];
191 SetSceneDebugOptions(new Dictionary<string, string>() { { key, value } });
192
193 MainConsole.Instance.OutputFormat("Set {0} debug scene {1} = {2}", m_scene.Name, key, value);
194 }
195 else
196 {
197 MainConsole.Instance.Output(
198 "Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false");
199 }
200 }
201
202 public void SetSceneDebugOptions(Dictionary<string, string> options)
203 {
204 if (options.ContainsKey("active"))
205 {
206 bool active;
207
208 if (bool.TryParse(options["active"], out active))
209 m_scene.Active = active;
210 }
211
212 if (options.ContainsKey("animations"))
213 {
214 bool active;
215
216 if (bool.TryParse(options["animations"], out active))
217 m_scene.DebugAnimations = active;
218 }
219
220 if (options.ContainsKey("pbackup"))
221 {
222 bool active;
223
224 if (bool.TryParse(options["pbackup"], out active))
225 m_scene.PeriodicBackup = active;
226 }
227
228 if (options.ContainsKey("scripting"))
229 {
230 bool enableScripts = true;
231 if (bool.TryParse(options["scripting"], out enableScripts))
232 m_scene.ScriptsEnabled = enableScripts;
233 }
234
235 if (options.ContainsKey("physics"))
236 {
237 bool enablePhysics;
238 if (bool.TryParse(options["physics"], out enablePhysics))
239 m_scene.PhysicsEnabled = enablePhysics;
240 }
241
242// if (options.ContainsKey("collisions"))
243// {
244// // TODO: Implement. If false, should stop objects colliding, though possibly should still allow
245// // the avatar themselves to collide with the ground.
246// }
247
248 if (options.ContainsKey("teleport"))
249 {
250 bool enableTeleportDebugging;
251 if (bool.TryParse(options["teleport"], out enableTeleportDebugging))
252 m_scene.DebugTeleporting = enableTeleportDebugging;
253 }
254
255 if (options.ContainsKey("updates"))
256 {
257 bool enableUpdateDebugging;
258 if (bool.TryParse(options["updates"], out enableUpdateDebugging))
259 {
260 m_scene.DebugUpdates = enableUpdateDebugging;
261 GcNotify.Enabled = enableUpdateDebugging;
262 }
263 }
264 }
265 }
266} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
index fb9cb66..6fd6f7e 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
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..0816b7b 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
@@ -100,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
100 102
101 public override float Simulate(float timeStep) 103 public override float Simulate(float timeStep)
102 { 104 {
105// Console.WriteLine("Simulating");
106
103 float fps = 0; 107 float fps = 0;
104 for (int i = 0; i < _actors.Count; ++i) 108 for (int i = 0; i < _actors.Count; ++i)
105 { 109 {
@@ -107,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
107 Vector3 actorPosition = actor.Position; 111 Vector3 actorPosition = actor.Position;
108 Vector3 actorVelocity = actor.Velocity; 112 Vector3 actorVelocity = actor.Velocity;
109 113
110 actorPosition.X += actor.Velocity.X*timeStep; 114// Console.WriteLine(
111 actorPosition.Y += actor.Velocity.Y*timeStep; 115// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
116
117 actorPosition.X += actor.Velocity.X * timeStep;
118 actorPosition.Y += actor.Velocity.Y * timeStep;
112 119
113 if (actor.Position.Y < 0) 120 if (actor.Position.Y < 0)
114 { 121 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
new file mode 100755
index 0000000..77ea3ed
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -0,0 +1,1987 @@
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.SetShapeCollisionMargin(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 Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
442 Vector3 frameInBloc, Quaternion frameInBrot,
443 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
444{
445 BulletWorldUnman worldu = world as BulletWorldUnman;
446 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
447 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
448 frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
449}
450
451public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
452 Vector3 frame1loc, Quaternion frame1rot,
453 Vector3 frame2loc, Quaternion frame2rot,
454 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
455{
456 BulletWorldUnman worldu = world as BulletWorldUnman;
457 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
458 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
459 return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
460 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
461}
462
463public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
464 Vector3 pivotinA, Vector3 pivotinB,
465 Vector3 axisInA, Vector3 axisInB,
466 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
467{
468 BulletWorldUnman worldu = world as BulletWorldUnman;
469 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
470 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
471 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
472 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
473}
474
475public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
476 Vector3 frame1loc, Quaternion frame1rot,
477 Vector3 frame2loc, Quaternion frame2rot,
478 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
479{
480 BulletWorldUnman worldu = world as BulletWorldUnman;
481 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
482 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
483 return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
484 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
485}
486
487public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
488 Vector3 frame1loc, Quaternion frame1rot,
489 Vector3 frame2loc, Quaternion frame2rot,
490 bool disableCollisionsBetweenLinkedBodies)
491{
492 BulletWorldUnman worldu = world as BulletWorldUnman;
493 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
494 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
495 return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
496 frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
497}
498
499public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
500 Vector3 axisInA, Vector3 axisInB,
501 float ratio, bool disableCollisionsBetweenLinkedBodies)
502{
503 BulletWorldUnman worldu = world as BulletWorldUnman;
504 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
505 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
506 return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
507 ratio, disableCollisionsBetweenLinkedBodies));
508}
509
510public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
511 Vector3 pivotInA, Vector3 pivotInB,
512 bool disableCollisionsBetweenLinkedBodies)
513{
514 BulletWorldUnman worldu = world as BulletWorldUnman;
515 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
516 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
517 return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
518 disableCollisionsBetweenLinkedBodies));
519}
520
521public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
522{
523 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
524 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
525}
526
527public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
528{
529 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
530 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
531}
532
533public override bool SetFrames(BulletConstraint constrain,
534 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
535{
536 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
537 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
538}
539
540public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
541{
542 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
543 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
544}
545
546public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
547{
548 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
549 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
550}
551
552public override bool UseFrameOffset(BulletConstraint constrain, float enable)
553{
554 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
555 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
556}
557
558public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
559{
560 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
561 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
562}
563
564public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
565{
566 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
567 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
568}
569
570public override bool CalculateTransforms(BulletConstraint constrain)
571{
572 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
573 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
574}
575
576public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
577{
578 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
579 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
580}
581
582public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
583{
584 BulletWorldUnman worldu = world as BulletWorldUnman;
585 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
586 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
587}
588
589// =====================================================================================
590// btCollisionWorld entries
591public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
592{
593 BulletWorldUnman worldu = world as BulletWorldUnman;
594 BulletBodyUnman bodyu = obj as BulletBodyUnman;
595 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
596}
597
598public override void UpdateAabbs(BulletWorld world)
599{
600 BulletWorldUnman worldu = world as BulletWorldUnman;
601 BSAPICPP.UpdateAabbs2(worldu.ptr);
602}
603
604public override bool GetForceUpdateAllAabbs(BulletWorld world)
605{
606 BulletWorldUnman worldu = world as BulletWorldUnman;
607 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
608}
609
610public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
611{
612 BulletWorldUnman worldu = world as BulletWorldUnman;
613 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
614}
615
616// =====================================================================================
617// btDynamicsWorld entries
618public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
619{
620 BulletWorldUnman worldu = world as BulletWorldUnman;
621 BulletBodyUnman bodyu = obj as BulletBodyUnman;
622
623 // Bullet resets several variables when an object is added to the world.
624 // Gravity is reset to world default depending on the static/dynamic
625 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
626 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
627
628 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
629
630 if (ret)
631 {
632 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
633 obj.ApplyCollisionMask(world.physicsScene);
634 }
635 return ret;
636}
637
638public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
639{
640 BulletWorldUnman worldu = world as BulletWorldUnman;
641 BulletBodyUnman bodyu = obj as BulletBodyUnman;
642 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
643}
644
645public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
646{
647 BulletWorldUnman worldu = world as BulletWorldUnman;
648 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
649 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
650}
651
652public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
653{
654 BulletWorldUnman worldu = world as BulletWorldUnman;
655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
656 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
657}
658// =====================================================================================
659// btCollisionObject entries
660public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
661{
662 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
663 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
664}
665
666public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
667{
668 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
669 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
670}
671
672public override bool HasAnisotripicFriction(BulletConstraint constrain)
673{
674 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
675 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
676}
677
678public override void SetContactProcessingThreshold(BulletBody obj, float val)
679{
680 BulletBodyUnman bodyu = obj as BulletBodyUnman;
681 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
682}
683
684public override float GetContactProcessingThreshold(BulletBody obj)
685{
686 BulletBodyUnman bodyu = obj as BulletBodyUnman;
687 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
688}
689
690public override bool IsStaticObject(BulletBody obj)
691{
692 BulletBodyUnman bodyu = obj as BulletBodyUnman;
693 return BSAPICPP.IsStaticObject2(bodyu.ptr);
694}
695
696public override bool IsKinematicObject(BulletBody obj)
697{
698 BulletBodyUnman bodyu = obj as BulletBodyUnman;
699 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
700}
701
702public override bool IsStaticOrKinematicObject(BulletBody obj)
703{
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
706}
707
708public override bool HasContactResponse(BulletBody obj)
709{
710 BulletBodyUnman bodyu = obj as BulletBodyUnman;
711 return BSAPICPP.HasContactResponse2(bodyu.ptr);
712}
713
714public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
715{
716 BulletWorldUnman worldu = world as BulletWorldUnman;
717 BulletBodyUnman bodyu = obj as BulletBodyUnman;
718 BulletShapeUnman shapeu = shape as BulletShapeUnman;
719 if (worldu != null && bodyu != null)
720 {
721 // Special case to allow the caller to zero out the reference to any physical shape
722 if (shapeu != null)
723 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
724 else
725 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
726 }
727}
728
729public override BulletShape GetCollisionShape(BulletBody obj)
730{
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
733}
734
735public override int GetActivationState(BulletBody obj)
736{
737 BulletBodyUnman bodyu = obj as BulletBodyUnman;
738 return BSAPICPP.GetActivationState2(bodyu.ptr);
739}
740
741public override void SetActivationState(BulletBody obj, int state)
742{
743 BulletBodyUnman bodyu = obj as BulletBodyUnman;
744 BSAPICPP.SetActivationState2(bodyu.ptr, state);
745}
746
747public override void SetDeactivationTime(BulletBody obj, float dtime)
748{
749 BulletBodyUnman bodyu = obj as BulletBodyUnman;
750 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
751}
752
753public override float GetDeactivationTime(BulletBody obj)
754{
755 BulletBodyUnman bodyu = obj as BulletBodyUnman;
756 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
757}
758
759public override void ForceActivationState(BulletBody obj, ActivationState state)
760{
761 BulletBodyUnman bodyu = obj as BulletBodyUnman;
762 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
763}
764
765public override void Activate(BulletBody obj, bool forceActivation)
766{
767 BulletBodyUnman bodyu = obj as BulletBodyUnman;
768 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
769}
770
771public override bool IsActive(BulletBody obj)
772{
773 BulletBodyUnman bodyu = obj as BulletBodyUnman;
774 return BSAPICPP.IsActive2(bodyu.ptr);
775}
776
777public override void SetRestitution(BulletBody obj, float val)
778{
779 BulletBodyUnman bodyu = obj as BulletBodyUnman;
780 BSAPICPP.SetRestitution2(bodyu.ptr, val);
781}
782
783public override float GetRestitution(BulletBody obj)
784{
785 BulletBodyUnman bodyu = obj as BulletBodyUnman;
786 return BSAPICPP.GetRestitution2(bodyu.ptr);
787}
788
789public override void SetFriction(BulletBody obj, float val)
790{
791 BulletBodyUnman bodyu = obj as BulletBodyUnman;
792 BSAPICPP.SetFriction2(bodyu.ptr, val);
793}
794
795public override float GetFriction(BulletBody obj)
796{
797 BulletBodyUnman bodyu = obj as BulletBodyUnman;
798 return BSAPICPP.GetFriction2(bodyu.ptr);
799}
800
801public override Vector3 GetPosition(BulletBody obj)
802{
803 BulletBodyUnman bodyu = obj as BulletBodyUnman;
804 return BSAPICPP.GetPosition2(bodyu.ptr);
805}
806
807public override Quaternion GetOrientation(BulletBody obj)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 return BSAPICPP.GetOrientation2(bodyu.ptr);
811}
812
813public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
817}
818
819 /*
820public override IntPtr GetBroadphaseHandle(BulletBody obj)
821{
822 BulletBodyUnman bodyu = obj as BulletBodyUnman;
823 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
824}
825
826public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
827{
828 BulletBodyUnman bodyu = obj as BulletBodyUnman;
829 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
830}
831 */
832
833public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
834{
835 BulletBodyUnman bodyu = obj as BulletBodyUnman;
836 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
837}
838
839public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
840{
841 BulletBodyUnman bodyu = obj as BulletBodyUnman;
842 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
843}
844
845public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
846{
847 BulletBodyUnman bodyu = obj as BulletBodyUnman;
848 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
849}
850
851public override float GetHitFraction(BulletBody obj)
852{
853 BulletBodyUnman bodyu = obj as BulletBodyUnman;
854 return BSAPICPP.GetHitFraction2(bodyu.ptr);
855}
856
857public override void SetHitFraction(BulletBody obj, float val)
858{
859 BulletBodyUnman bodyu = obj as BulletBodyUnman;
860 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
861}
862
863public override CollisionFlags GetCollisionFlags(BulletBody obj)
864{
865 BulletBodyUnman bodyu = obj as BulletBodyUnman;
866 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
867}
868
869public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
870{
871 BulletBodyUnman bodyu = obj as BulletBodyUnman;
872 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
873}
874
875public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
876{
877 BulletBodyUnman bodyu = obj as BulletBodyUnman;
878 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
879}
880
881public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
882{
883 BulletBodyUnman bodyu = obj as BulletBodyUnman;
884 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
885}
886
887public override float GetCcdMotionThreshold(BulletBody obj)
888{
889 BulletBodyUnman bodyu = obj as BulletBodyUnman;
890 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
891}
892
893
894public override void SetCcdMotionThreshold(BulletBody obj, float val)
895{
896 BulletBodyUnman bodyu = obj as BulletBodyUnman;
897 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
898}
899
900public override float GetCcdSweptSphereRadius(BulletBody obj)
901{
902 BulletBodyUnman bodyu = obj as BulletBodyUnman;
903 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
904}
905
906public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
907{
908 BulletBodyUnman bodyu = obj as BulletBodyUnman;
909 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
910}
911
912public override IntPtr GetUserPointer(BulletBody obj)
913{
914 BulletBodyUnman bodyu = obj as BulletBodyUnman;
915 return BSAPICPP.GetUserPointer2(bodyu.ptr);
916}
917
918public override void SetUserPointer(BulletBody obj, IntPtr val)
919{
920 BulletBodyUnman bodyu = obj as BulletBodyUnman;
921 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
922}
923
924// =====================================================================================
925// btRigidBody entries
926public override void ApplyGravity(BulletBody obj)
927{
928 BulletBodyUnman bodyu = obj as BulletBodyUnman;
929 BSAPICPP.ApplyGravity2(bodyu.ptr);
930}
931
932public override void SetGravity(BulletBody obj, Vector3 val)
933{
934 BulletBodyUnman bodyu = obj as BulletBodyUnman;
935 BSAPICPP.SetGravity2(bodyu.ptr, val);
936}
937
938public override Vector3 GetGravity(BulletBody obj)
939{
940 BulletBodyUnman bodyu = obj as BulletBodyUnman;
941 return BSAPICPP.GetGravity2(bodyu.ptr);
942}
943
944public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
945{
946 BulletBodyUnman bodyu = obj as BulletBodyUnman;
947 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
948}
949
950public override void SetLinearDamping(BulletBody obj, float lin_damping)
951{
952 BulletBodyUnman bodyu = obj as BulletBodyUnman;
953 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
954}
955
956public override void SetAngularDamping(BulletBody obj, float ang_damping)
957{
958 BulletBodyUnman bodyu = obj as BulletBodyUnman;
959 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
960}
961
962public override float GetLinearDamping(BulletBody obj)
963{
964 BulletBodyUnman bodyu = obj as BulletBodyUnman;
965 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
966}
967
968public override float GetAngularDamping(BulletBody obj)
969{
970 BulletBodyUnman bodyu = obj as BulletBodyUnman;
971 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
972}
973
974public override float GetLinearSleepingThreshold(BulletBody obj)
975{
976 BulletBodyUnman bodyu = obj as BulletBodyUnman;
977 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
978}
979
980public override void ApplyDamping(BulletBody obj, float timeStep)
981{
982 BulletBodyUnman bodyu = obj as BulletBodyUnman;
983 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
984}
985
986public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
987{
988 BulletBodyUnman bodyu = obj as BulletBodyUnman;
989 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
990}
991
992public override Vector3 GetLinearFactor(BulletBody obj)
993{
994 BulletBodyUnman bodyu = obj as BulletBodyUnman;
995 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
996}
997
998public override void SetLinearFactor(BulletBody obj, Vector3 factor)
999{
1000 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1001 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
1002}
1003
1004public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
1005{
1006 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1007 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
1008}
1009
1010// Add a force to the object as if its mass is one.
1011// Deep down in Bullet: m_totalForce += force*m_linearFactor;
1012public override void ApplyCentralForce(BulletBody obj, Vector3 force)
1013{
1014 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1015 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
1016}
1017
1018// Set the force being applied to the object as if its mass is one.
1019public override void SetObjectForce(BulletBody obj, Vector3 force)
1020{
1021 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1022 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
1023}
1024
1025public override Vector3 GetTotalForce(BulletBody obj)
1026{
1027 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1028 return BSAPICPP.GetTotalForce2(bodyu.ptr);
1029}
1030
1031public override Vector3 GetTotalTorque(BulletBody obj)
1032{
1033 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1034 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
1035}
1036
1037public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
1038{
1039 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1040 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
1041}
1042
1043public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
1044{
1045 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1046 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
1047}
1048
1049public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
1050{
1051 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1052 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
1053}
1054
1055// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
1056public override void ApplyTorque(BulletBody obj, Vector3 torque)
1057{
1058 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1059 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
1060}
1061
1062// Apply force at the given point. Will add torque to the object.
1063// Deep down in Bullet: applyCentralForce(force);
1064// applyTorque(rel_pos.cross(force*m_linearFactor));
1065public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
1066{
1067 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1068 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1069}
1070
1071// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1072// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1073public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1074{
1075 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1076 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1077}
1078
1079// Apply impulse to the object's torque. Force is scaled by object's mass.
1080// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1081public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1082{
1083 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1084 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1085}
1086
1087// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1088// Deep down in Bullet: applyCentralImpulse(impulse);
1089// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1090public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1091{
1092 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1093 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1094}
1095
1096public override void ClearForces(BulletBody obj)
1097{
1098 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1099 BSAPICPP.ClearForces2(bodyu.ptr);
1100}
1101
1102public override void ClearAllForces(BulletBody obj)
1103{
1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1105 BSAPICPP.ClearAllForces2(bodyu.ptr);
1106}
1107
1108public override void UpdateInertiaTensor(BulletBody obj)
1109{
1110 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1111 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1112}
1113
1114public override Vector3 GetLinearVelocity(BulletBody obj)
1115{
1116 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1117 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1118}
1119
1120public override Vector3 GetAngularVelocity(BulletBody obj)
1121{
1122 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1123 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1124}
1125
1126public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1127{
1128 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1129 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1130}
1131
1132public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1133{
1134 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1135 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1136}
1137
1138public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1139{
1140 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1141 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1142}
1143
1144public override void Translate(BulletBody obj, Vector3 trans)
1145{
1146 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1147 BSAPICPP.Translate2(bodyu.ptr, trans);
1148}
1149
1150public override void UpdateDeactivation(BulletBody obj, float timeStep)
1151{
1152 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1153 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1154}
1155
1156public override bool WantsSleeping(BulletBody obj)
1157{
1158 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1159 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1160}
1161
1162public override void SetAngularFactor(BulletBody obj, float factor)
1163{
1164 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1165 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1166}
1167
1168public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1169{
1170 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1171 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1172}
1173
1174public override Vector3 GetAngularFactor(BulletBody obj)
1175{
1176 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1177 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1178}
1179
1180public override bool IsInWorld(BulletWorld world, BulletBody obj)
1181{
1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1183 return BSAPICPP.IsInWorld2(bodyu.ptr);
1184}
1185
1186public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1187{
1188 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1189 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1190 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1191}
1192
1193public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1194{
1195 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1196 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1197 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1198}
1199
1200public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1201{
1202 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1203 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1204}
1205
1206public override int GetNumConstraintRefs(BulletBody obj)
1207{
1208 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1209 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1210}
1211
1212public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1213{
1214 BulletBodyUnman bodyu = body as BulletBodyUnman;
1215 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1216}
1217
1218// =====================================================================================
1219// btCollisionShape entries
1220
1221public override float GetAngularMotionDisc(BulletShape shape)
1222{
1223 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1224 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1225}
1226
1227public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1228{
1229 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1230 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1231}
1232
1233public override bool IsPolyhedral(BulletShape shape)
1234{
1235 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1236 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1237}
1238
1239public override bool IsConvex2d(BulletShape shape)
1240{
1241 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1242 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1243}
1244
1245public override bool IsConvex(BulletShape shape)
1246{
1247 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1248 return BSAPICPP.IsConvex2(shapeu.ptr);
1249}
1250
1251public override bool IsNonMoving(BulletShape shape)
1252{
1253 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1254 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1255}
1256
1257public override bool IsConcave(BulletShape shape)
1258{
1259 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1260 return BSAPICPP.IsConcave2(shapeu.ptr);
1261}
1262
1263public override bool IsCompound(BulletShape shape)
1264{
1265 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1266 return BSAPICPP.IsCompound2(shapeu.ptr);
1267}
1268
1269public override bool IsSoftBody(BulletShape shape)
1270{
1271 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1272 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1273}
1274
1275public override bool IsInfinite(BulletShape shape)
1276{
1277 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1278 return BSAPICPP.IsInfinite2(shapeu.ptr);
1279}
1280
1281public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1282{
1283 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1284 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1285}
1286
1287public override Vector3 GetLocalScaling(BulletShape shape)
1288{
1289 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1290 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1291}
1292
1293public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1294{
1295 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1296 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1297}
1298
1299public override int GetShapeType(BulletShape shape)
1300{
1301 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1302 return BSAPICPP.GetShapeType2(shapeu.ptr);
1303}
1304
1305public override void SetMargin(BulletShape shape, float val)
1306{
1307 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1308 BSAPICPP.SetMargin2(shapeu.ptr, val);
1309}
1310
1311public override float GetMargin(BulletShape shape)
1312{
1313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1314 return BSAPICPP.GetMargin2(shapeu.ptr);
1315}
1316
1317// =====================================================================================
1318// Debugging
1319public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1320{
1321 BulletWorldUnman worldu = world as BulletWorldUnman;
1322 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1323 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1324}
1325
1326public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1327{
1328 BulletWorldUnman worldu = world as BulletWorldUnman;
1329 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1330 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1331}
1332
1333public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1334{
1335 BulletWorldUnman worldu = world as BulletWorldUnman;
1336 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1337 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1338}
1339
1340public override void DumpActivationInfo(BulletWorld world)
1341{
1342 BulletWorldUnman worldu = world as BulletWorldUnman;
1343 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1344}
1345
1346public override void DumpAllInfo(BulletWorld world)
1347{
1348 BulletWorldUnman worldu = world as BulletWorldUnman;
1349 BSAPICPP.DumpAllInfo2(worldu.ptr);
1350}
1351
1352public override void DumpPhysicsStatistics(BulletWorld world)
1353{
1354 BulletWorldUnman worldu = world as BulletWorldUnman;
1355 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1356}
1357public override void ResetBroadphasePool(BulletWorld world)
1358{
1359 BulletWorldUnman worldu = world as BulletWorldUnman;
1360 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1361}
1362public override void ResetConstraintSolver(BulletWorld world)
1363{
1364 BulletWorldUnman worldu = world as BulletWorldUnman;
1365 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1366}
1367
1368// =====================================================================================
1369// =====================================================================================
1370// =====================================================================================
1371// =====================================================================================
1372// =====================================================================================
1373// The actual interface to the unmanaged code
1374static class BSAPICPP
1375{
1376// ===============================================================================
1377// Link back to the managed code for outputting log messages
1378[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1379public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1380
1381// ===============================================================================
1382// Initialization and simulation
1383[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1384public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1385 int maxCollisions, IntPtr collisionArray,
1386 int maxUpdates, IntPtr updateArray,
1387 DebugLogCallback logRoutine);
1388
1389[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1390public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1391 out int updatedEntityCount, out int collidersCount);
1392
1393[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1394public static extern void Shutdown2(IntPtr sim);
1395
1396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1397public static extern bool PushUpdate2(IntPtr obj);
1398
1399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1400public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1401
1402// =====================================================================================
1403// Mesh, hull, shape and body creation helper routines
1404[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1405public static extern IntPtr CreateMeshShape2(IntPtr world,
1406 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1407 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1408
1409[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1410public static extern IntPtr CreateHullShape2(IntPtr world,
1411 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1412
1413[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1414public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1415
1416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1417public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1418
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1420public static extern bool IsNativeShape2(IntPtr shape);
1421
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1423public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1424
1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1426public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1427
1428[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1429public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1430
1431[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1432public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1433
1434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1435public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1436
1437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1438public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1439
1440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1441public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1442
1443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1444public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1445
1446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1447public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1448
1449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1450public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1451
1452[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1453public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1454
1455[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1456public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1457
1458[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1459public static extern int GetBodyType2(IntPtr obj);
1460
1461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1462public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1463
1464[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1465public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1466
1467[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1468public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1469
1470[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1471public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1472
1473// =====================================================================================
1474// Terrain creation and helper routines
1475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1476public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1477
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1480 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1481 float scaleFactor, float collisionMargin);
1482
1483// =====================================================================================
1484// Constraint creation and helper routines
1485[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1486public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1487 Vector3 frame1loc, Quaternion frame1rot,
1488 Vector3 frame2loc, Quaternion frame2rot,
1489 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1490
1491[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1492public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1493 Vector3 joinPoint,
1494 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1495
1496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1497public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
1498 Vector3 frameInBloc, Quaternion frameInBrot,
1499 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
1500
1501[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1502public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1503 Vector3 frame1loc, Quaternion frame1rot,
1504 Vector3 frame2loc, Quaternion frame2rot,
1505 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1506
1507[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1508public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1509 Vector3 pivotinA, Vector3 pivotinB,
1510 Vector3 axisInA, Vector3 axisInB,
1511 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1512
1513[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1514public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1515 Vector3 frameInAloc, Quaternion frameInArot,
1516 Vector3 frameInBloc, Quaternion frameInBrot,
1517 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1518
1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1520public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1521 Vector3 frameInAloc, Quaternion frameInArot,
1522 Vector3 frameInBloc, Quaternion frameInBrot,
1523 bool disableCollisionsBetweenLinkedBodies);
1524
1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1526public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1527 Vector3 axisInA, Vector3 axisInB,
1528 float ratio, bool disableCollisionsBetweenLinkedBodies);
1529
1530[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1531public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1532 Vector3 pivotInA, Vector3 pivotInB,
1533 bool disableCollisionsBetweenLinkedBodies);
1534
1535
1536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1537public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1538
1539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1540public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1541
1542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1543public static extern bool SetFrames2(IntPtr constrain,
1544 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1545
1546[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1547public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1548
1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1553public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1554
1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1556public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1557
1558[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1559public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1560
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern bool CalculateTransforms2(IntPtr constrain);
1563
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1569
1570// =====================================================================================
1571// btCollisionWorld entries
1572[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1573public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1574
1575[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1576public static extern void UpdateAabbs2(IntPtr world);
1577
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1583
1584// =====================================================================================
1585// btDynamicsWorld entries
1586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1587public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1588
1589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1590public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1591
1592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1593public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1594
1595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1596public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1597// =====================================================================================
1598// btCollisionObject entries
1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1601
1602[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1603public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1604
1605[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1606public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1607
1608[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1609public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1610
1611[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1612public static extern float GetContactProcessingThreshold2(IntPtr obj);
1613
1614[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1615public static extern bool IsStaticObject2(IntPtr obj);
1616
1617[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1618public static extern bool IsKinematicObject2(IntPtr obj);
1619
1620[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1621public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1622
1623[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1624public static extern bool HasContactResponse2(IntPtr obj);
1625
1626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1627public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1628
1629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1630public static extern IntPtr GetCollisionShape2(IntPtr obj);
1631
1632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1633public static extern int GetActivationState2(IntPtr obj);
1634
1635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1636public static extern void SetActivationState2(IntPtr obj, int state);
1637
1638[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1639public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1640
1641[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1642public static extern float GetDeactivationTime2(IntPtr obj);
1643
1644[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1645public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1646
1647[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1648public static extern void Activate2(IntPtr obj, bool forceActivation);
1649
1650[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1651public static extern bool IsActive2(IntPtr obj);
1652
1653[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1654public static extern void SetRestitution2(IntPtr obj, float val);
1655
1656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1657public static extern float GetRestitution2(IntPtr obj);
1658
1659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1660public static extern void SetFriction2(IntPtr obj, float val);
1661
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern float GetFriction2(IntPtr obj);
1664
1665 /* Haven't defined the type 'Transform'
1666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1667public static extern Transform GetWorldTransform2(IntPtr obj);
1668
1669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1670public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1671 */
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern Vector3 GetPosition2(IntPtr obj);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern Quaternion GetOrientation2(IntPtr obj);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1687
1688 /*
1689[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1690public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1691
1692[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1693public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1694 */
1695
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1698
1699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1700public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1701
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern float GetHitFraction2(IntPtr obj);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern void SetHitFraction2(IntPtr obj, float val);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1713
1714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1715public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1716
1717[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1718public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1719
1720[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1721public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1722
1723[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1724public static extern float GetCcdMotionThreshold2(IntPtr obj);
1725
1726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1727public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1728
1729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1730public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1731
1732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1733public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1734
1735[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1736public static extern IntPtr GetUserPointer2(IntPtr obj);
1737
1738[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1739public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1740
1741// =====================================================================================
1742// btRigidBody entries
1743[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1744public static extern void ApplyGravity2(IntPtr obj);
1745
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern void SetGravity2(IntPtr obj, Vector3 val);
1748
1749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1750public static extern Vector3 GetGravity2(IntPtr obj);
1751
1752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1753public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1754
1755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1756public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1757
1758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1759public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1760
1761[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1762public static extern float GetLinearDamping2(IntPtr obj);
1763
1764[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1765public static extern float GetAngularDamping2(IntPtr obj);
1766
1767[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1768public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1769
1770[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1771public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1772
1773[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1774public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1775
1776[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1777public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1778
1779[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1780public static extern Vector3 GetLinearFactor2(IntPtr obj);
1781
1782[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1783public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1784
1785 /*
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1788 */
1789
1790[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1791public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1792
1793// Add a force to the object as if its mass is one.
1794[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1795public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1796
1797// Set the force being applied to the object as if its mass is one.
1798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1799public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1800
1801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1802public static extern Vector3 GetTotalForce2(IntPtr obj);
1803
1804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1805public static extern Vector3 GetTotalTorque2(IntPtr obj);
1806
1807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1808public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1809
1810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1811public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1812
1813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1814public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1815
1816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1817public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1818
1819// Apply force at the given point. Will add torque to the object.
1820[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1821public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1822
1823// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1824[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1825public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1826
1827// Apply impulse to the object's torque. Force is scaled by object's mass.
1828[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1829public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1830
1831// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1834
1835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1836public static extern void ClearForces2(IntPtr obj);
1837
1838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1839public static extern void ClearAllForces2(IntPtr obj);
1840
1841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1842public static extern void UpdateInertiaTensor2(IntPtr obj);
1843
1844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1845public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1846
1847 /*
1848[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1849public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1850 */
1851
1852[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1853public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1854
1855[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1856public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1857
1858[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1859public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1860
1861[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1862public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1863
1864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1865public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1866
1867[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1868public static extern void Translate2(IntPtr obj, Vector3 trans);
1869
1870[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1871public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1872
1873[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1874public static extern bool WantsSleeping2(IntPtr obj);
1875
1876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1877public static extern void SetAngularFactor2(IntPtr obj, float factor);
1878
1879[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1880public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1881
1882[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1883public static extern Vector3 GetAngularFactor2(IntPtr obj);
1884
1885[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1886public static extern bool IsInWorld2(IntPtr obj);
1887
1888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1889public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1890
1891[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1892public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1893
1894[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1895public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1896
1897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1898public static extern int GetNumConstraintRefs2(IntPtr obj);
1899
1900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1901public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1902
1903// =====================================================================================
1904// btCollisionShape entries
1905
1906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1907public static extern float GetAngularMotionDisc2(IntPtr shape);
1908
1909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1910public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1911
1912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1913public static extern bool IsPolyhedral2(IntPtr shape);
1914
1915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1916public static extern bool IsConvex2d2(IntPtr shape);
1917
1918[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1919public static extern bool IsConvex2(IntPtr shape);
1920
1921[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1922public static extern bool IsNonMoving2(IntPtr shape);
1923
1924[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1925public static extern bool IsConcave2(IntPtr shape);
1926
1927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1928public static extern bool IsCompound2(IntPtr shape);
1929
1930[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1931public static extern bool IsSoftBody2(IntPtr shape);
1932
1933[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1934public static extern bool IsInfinite2(IntPtr shape);
1935
1936[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1937public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1938
1939[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1940public static extern Vector3 GetLocalScaling2(IntPtr shape);
1941
1942[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1943public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1944
1945[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1946public static extern int GetShapeType2(IntPtr shape);
1947
1948[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1949public static extern void SetMargin2(IntPtr shape, float val);
1950
1951[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1952public static extern float GetMargin2(IntPtr shape);
1953
1954// =====================================================================================
1955// Debugging
1956[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1957public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1958
1959[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1960public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1961
1962[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1963public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1964
1965[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1966public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1967
1968[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1969public static extern void DumpActivationInfo2(IntPtr sim);
1970
1971[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1972public static extern void DumpAllInfo2(IntPtr sim);
1973
1974[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1975public static extern void DumpPhysicsStatistics2(IntPtr sim);
1976
1977[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1978public static extern void ResetBroadphasePool(IntPtr sim);
1979
1980[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1981public static extern void ResetConstraintSolver(IntPtr sim);
1982
1983}
1984
1985}
1986
1987}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
new file mode 100755
index 0000000..6fc10e9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -0,0 +1,2311 @@
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.Text;
32
33using OpenSim.Framework;
34
35using OpenMetaverse;
36
37using BulletXNA;
38using BulletXNA.LinearMath;
39using BulletXNA.BulletCollision;
40using BulletXNA.BulletDynamics;
41using BulletXNA.BulletCollision.CollisionDispatch;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public sealed class BSAPIXNA : BSAPITemplate
46{
47private sealed class BulletWorldXNA : BulletWorld
48{
49 public DiscreteDynamicsWorld world;
50 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
51 : base(id, physScene)
52 {
53 world = xx;
54 }
55}
56
57private sealed class BulletBodyXNA : BulletBody
58{
59 public CollisionObject body;
60 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
61
62 public BulletBodyXNA(uint id, CollisionObject xx)
63 : base(id)
64 {
65 body = xx;
66 }
67 public override bool HasPhysicalBody
68 {
69 get { return body != null; }
70 }
71 public override void Clear()
72 {
73 body = null;
74 }
75 public override string AddrString
76 {
77 get { return "XNARigidBody"; }
78 }
79}
80
81private sealed class BulletShapeXNA : BulletShape
82{
83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base()
86 {
87 shape = xx;
88 type = typ;
89 }
90 public override bool HasPhysicalShape
91 {
92 get { return shape != null; }
93 }
94 public override void Clear()
95 {
96 shape = null;
97 }
98 public override BulletShape Clone()
99 {
100 return new BulletShapeXNA(shape, type);
101 }
102 public override bool ReferenceSame(BulletShape other)
103 {
104 BulletShapeXNA otheru = other as BulletShapeXNA;
105 return (otheru != null) && (this.shape == otheru.shape);
106
107 }
108 public override string AddrString
109 {
110 get { return "XNACollisionShape"; }
111 }
112}
113private sealed class BulletConstraintXNA : BulletConstraint
114{
115 public TypedConstraint constrain;
116 public BulletConstraintXNA(TypedConstraint xx) : base()
117 {
118 constrain = xx;
119 }
120
121 public override void Clear()
122 {
123 constrain = null;
124 }
125 public override bool HasPhysicalConstraint { get { return constrain != null; } }
126
127 // Used for log messages for a unique display of the memory/object allocated to this instance
128 public override string AddrString
129 {
130 get { return "XNAConstraint"; }
131 }
132}
133 internal int m_maxCollisions;
134 internal CollisionDesc[] UpdatedCollisions;
135 internal int LastCollisionDesc = 0;
136 internal int m_maxUpdatesPerFrame;
137 internal int LastEntityProperty = 0;
138
139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141
142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; }
144
145 public override string BulletEngineName { get { return "BulletXNA"; } }
146 public override string BulletEngineVersion { get; protected set; }
147
148 public BSAPIXNA(string paramName, BSScene physScene)
149 {
150 PhysicsScene = physScene;
151 }
152
153 /// <summary>
154 ///
155 /// </summary>
156 /// <param name="p"></param>
157 /// <param name="p_2"></param>
158 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
159 {
160 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
161 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
162 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
163 if (body != null)
164 world.RemoveRigidBody(body);
165 else if (collisionObject != null)
166 world.RemoveCollisionObject(collisionObject);
167 else
168 return false;
169 return true;
170 }
171
172 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
177
178 return true;
179
180 }
181
182 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
183 {
184 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
185 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
186 world.RemoveConstraint(constraint);
187 return true;
188 }
189
190 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
191 {
192 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
193 collisionObject.SetRestitution(pRestitution);
194 }
195
196 public override int GetShapeType(BulletShape pShape)
197 {
198 CollisionShape shape = (pShape as BulletShapeXNA).shape;
199 return (int)shape.GetShapeType();
200 }
201 public override void SetMargin(BulletShape pShape, float pMargin)
202 {
203 CollisionShape shape = (pShape as BulletShapeXNA).shape;
204 shape.SetMargin(pMargin);
205 }
206
207 public override float GetMargin(BulletShape pShape)
208 {
209 CollisionShape shape = (pShape as BulletShapeXNA).shape;
210 return shape.GetMargin();
211 }
212
213 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
214 {
215 CollisionShape shape = (pShape as BulletShapeXNA).shape;
216 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
217 shape.SetLocalScaling(ref vec);
218
219 }
220
221 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
222 {
223 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
224 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
225 }
226
227 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
228 {
229 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
230 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
231 }
232
233 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
234 {
235 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
236 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
237 }
238
239 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
240 {
241 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
242 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
243 }
244
245 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
246 {
247 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
248 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
249 existingcollisionFlags |= pcollisionFlags;
250 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
251 return (CollisionFlags) (uint) existingcollisionFlags;
252 }
253
254 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
255 {
256 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
257 CollisionObject cbody = (pBody as BulletBodyXNA).body;
258 RigidBody rbody = cbody as RigidBody;
259
260 // Bullet resets several variables when an object is added to the world. In particular,
261 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
262 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
263 IndexedMatrix origPos = cbody.GetWorldTransform();
264 if (rbody != null)
265 {
266 IndexedVector3 origGrav = rbody.GetGravity();
267 world.AddRigidBody(rbody);
268 rbody.SetGravity(origGrav);
269 }
270 else
271 {
272 world.AddCollisionObject(cbody);
273 }
274 cbody.SetWorldTransform(origPos);
275
276 pBody.ApplyCollisionMask(pWorld.physicsScene);
277
278 //if (body.GetBroadphaseHandle() != null)
279 // world.UpdateSingleAabb(body);
280 return true;
281 }
282
283 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
284 {
285 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
286 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
287 }
288
289 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
290 {
291 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
292 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
293 world.UpdateSingleAabb(collisionObject);
294 }
295
296 public override void UpdateAabbs(BulletWorld pWorld) {
297 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
298 world.UpdateAabbs();
299 }
300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
302 return world.GetForceUpdateAllAabbs();
303
304 }
305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
306 {
307 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
308 world.SetForceUpdateAllAabbs(pForce);
309 }
310
311 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
312 {
313 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
314 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
315 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
316 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
317 return false;
318 return true;
319 }
320
321 public override void ClearAllForces(BulletBody pCollisionObject)
322 {
323 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
324 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
325 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
326 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
327 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
328
329 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
330
331 if (collisionObject is RigidBody)
332 {
333 RigidBody rigidbody = collisionObject as RigidBody;
334 rigidbody.SetLinearVelocity(zeroVector);
335 rigidbody.SetAngularVelocity(zeroVector);
336 rigidbody.ClearForces();
337 }
338 }
339
340 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
341 {
342 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
343 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
344 collisionObject.SetInterpolationAngularVelocity(ref vec);
345 }
346
347 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
348 {
349 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
350 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
351 body.SetAngularVelocity(ref vec);
352 }
353 public override Vector3 GetTotalForce(BulletBody pBody)
354 {
355 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
356 IndexedVector3 iv3 = body.GetTotalForce();
357 return new Vector3(iv3.X, iv3.Y, iv3.Z);
358 }
359 public override Vector3 GetTotalTorque(BulletBody pBody)
360 {
361 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
362 IndexedVector3 iv3 = body.GetTotalTorque();
363 return new Vector3(iv3.X, iv3.Y, iv3.Z);
364 }
365 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
366 {
367 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
368 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
369 return new Vector3(iv3.X, iv3.Y, iv3.Z);
370 }
371 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
372 {
373 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
374 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
375 body.SetInvInertiaDiagLocal(ref iv3);
376 }
377 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
378 {
379 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
380 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
381 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
382 body.ApplyForce(ref forceiv3, ref posiv3);
383 }
384 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
385 {
386 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
387 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
388 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
389 body.ApplyImpulse(ref impiv3, ref posiv3);
390 }
391
392 public override void ClearForces(BulletBody pBody)
393 {
394 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
395 body.ClearForces();
396 }
397
398 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
399 {
400 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
401 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
402 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
403 _orientation.W);
404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
405 mat._origin = vposition;
406 collisionObject.SetWorldTransform(mat);
407
408 }
409
410 public override Vector3 GetPosition(BulletBody pCollisionObject)
411 {
412 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
413 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
414 return new Vector3(pos.X, pos.Y, pos.Z);
415 }
416
417 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
418 {
419 CollisionShape shape = (pShape as BulletShapeXNA).shape;
420 IndexedVector3 inertia = IndexedVector3.Zero;
421 shape.CalculateLocalInertia(pphysMass, out inertia);
422 return new Vector3(inertia.X, inertia.Y, inertia.Z);
423 }
424
425 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
426 {
427 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
428 if (body != null) // Can't set mass props on collision object.
429 {
430 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
431 body.SetMassProps(pphysMass, inertia);
432 }
433 }
434
435
436 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
437 {
438 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
439 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
440 body.SetTotalForce(ref force);
441 }
442
443 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
444 {
445 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
446 collisionObject.SetFriction(_currentFriction);
447 }
448
449 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
450 {
451 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
452 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
453 body.SetLinearVelocity(velocity);
454 }
455
456 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
459 collisionObject.Activate(pforceactivation);
460
461 }
462
463 public override Quaternion GetOrientation(BulletBody pCollisionObject)
464 {
465 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
466 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
467 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
468 }
469
470 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
471 {
472 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
473 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
474 existingcollisionFlags &= ~pcollisionFlags;
475 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
476 return (CollisionFlags)(uint)existingcollisionFlags;
477 }
478
479 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
480 {
481 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
482 return collisionObject.GetCcdSquareMotionThreshold();
483 }
484
485 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
486 {
487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
488 return collisionObject.GetCcdSweptSphereRadius();
489
490 }
491
492 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
493 {
494 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
495 return (IntPtr)shape.GetUserPointer();
496 }
497
498 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
499 {
500 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
501 shape.SetUserPointer(val);
502 }
503
504 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
505 {
506 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
507 if (body != null) // Can't set collisionobject.set gravity
508 {
509 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
510 body.SetGravity(gravity);
511 }
512 }
513
514 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
515 {
516 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
517 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
518 world.RemoveConstraint(constraint);
519 return true;
520 }
521
522 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
523 {
524 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
525 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
526 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
527 constraint.SetLinearLowerLimit(lowlimit);
528 constraint.SetLinearUpperLimit(highlimit);
529 return true;
530 }
531
532 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
533 {
534 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
535 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
536 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
537 constraint.SetAngularLowerLimit(lowlimit);
538 constraint.SetAngularUpperLimit(highlimit);
539 return true;
540 }
541
542 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
543 {
544 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
545 constraint.SetOverrideNumSolverIterations((int)cnt);
546 }
547
548 public override bool CalculateTransforms(BulletConstraint pConstraint)
549 {
550 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
551 constraint.CalculateTransforms();
552 return true;
553 }
554
555 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
556 {
557 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
558 constraint.SetEnabled((p_2 == 0) ? false : true);
559 }
560
561
562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
565
566 {
567 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
568 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
569 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
570 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
571 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
572 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
573 frame1._origin = frame1v;
574
575 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
576 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
577 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
578 frame2._origin = frame1v;
579
580 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
581 puseLinearReferenceFrameA);
582 consttr.CalculateTransforms();
583 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
584
585 return new BulletConstraintXNA(consttr);
586 }
587
588 public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
589 Vector3 pframe1, Quaternion pframe1rot,
590 bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
591 {
592 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
593 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
594 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
595 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
596 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
597 frame1._origin = frame1v;
598
599 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
600 consttr.CalculateTransforms();
601 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
602
603 return new BulletConstraintXNA(consttr);
604 }
605
606 /// <summary>
607 ///
608 /// </summary>
609 /// <param name="pWorld"></param>
610 /// <param name="pBody1"></param>
611 /// <param name="pBody2"></param>
612 /// <param name="pjoinPoint"></param>
613 /// <param name="puseLinearReferenceFrameA"></param>
614 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
615 /// <returns></returns>
616 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
617 {
618 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
619 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
620 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
621 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
622 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
623
624 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
625 IndexedMatrix mat = IndexedMatrix.Identity;
626 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
627 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
628 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
629
630 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
631 consttr.CalculateTransforms();
632 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
633
634 return new BulletConstraintXNA(consttr);
635 }
636 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
637 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
638 {
639 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
640 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
641 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
642 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
643 frame1._origin = frame1v;
644
645 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
646 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
647 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
648 frame2._origin = frame1v;
649 constraint.SetFrames(ref frame1, ref frame2);
650 return true;
651 }
652
653 public override Vector3 GetLinearVelocity(BulletBody pBody)
654 {
655 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
656 IndexedVector3 iv3 = body.GetLinearVelocity();
657 return new Vector3(iv3.X, iv3.Y, iv3.Z);
658 }
659 public override Vector3 GetAngularVelocity(BulletBody pBody)
660 {
661 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
662 IndexedVector3 iv3 = body.GetAngularVelocity();
663 return new Vector3(iv3.X, iv3.Y, iv3.Z);
664 }
665 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
666 {
667 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
668 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
669 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
670 return new Vector3(iv3.X, iv3.Y, iv3.Z);
671 }
672 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
673 {
674 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
675 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
676 }
677 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
678 {
679 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
680 body.UpdateDeactivation(timeStep);
681 }
682
683 public override bool WantsSleeping(BulletBody pBody)
684 {
685 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
686 return body.WantsSleeping();
687 }
688
689 public override void SetAngularFactor(BulletBody pBody, float factor)
690 {
691 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
692 body.SetAngularFactor(factor);
693 }
694
695 public override Vector3 GetAngularFactor(BulletBody pBody)
696 {
697 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
698 IndexedVector3 iv3 = body.GetAngularFactor();
699 return new Vector3(iv3.X, iv3.Y, iv3.Z);
700 }
701
702 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
703 {
704 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
705 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
706 return world.IsInWorld(collisionObject);
707 }
708
709 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
710 {
711 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
712 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
713 body.AddConstraintRef(constrain);
714 }
715
716 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
717 {
718 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
719 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
720 body.RemoveConstraintRef(constrain);
721 }
722
723 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
724 {
725 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
726 return new BulletConstraintXNA(body.GetConstraintRef(index));
727 }
728
729 public override int GetNumConstraintRefs(BulletBody pBody)
730 {
731 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
732 return body.GetNumConstraintRefs();
733 }
734
735 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
736 {
737 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
738 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
739 collisionObject.SetInterpolationLinearVelocity(ref velocity);
740 }
741
742 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
743 {
744 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
745 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
746 return true;
747 }
748 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
749 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
750 {
751 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
752 constraint.SetBreakingImpulseThreshold(threshold);
753 return true;
754 }
755 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
756 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
757 {
758 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
759 float lineardamping = body.GetLinearDamping();
760 body.SetDamping(lineardamping, angularDamping);
761
762 }
763
764 public override void UpdateInertiaTensor(BulletBody pBody)
765 {
766 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
767 if (body != null) // can't update inertia tensor on CollisionObject
768 body.UpdateInertiaTensor();
769 }
770
771 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
772 {
773 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
774 shape.RecalculateLocalAabb();
775 }
776
777 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
778 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
779 {
780 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
781 uint flags = (uint)collisionObject.GetCollisionFlags();
782 return (CollisionFlags) flags;
783 }
784
785 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
786 {
787 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
788 body.SetDamping(pLinear, pAngular);
789 }
790 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
791 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
792 {
793 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
794 collisionObject.SetDeactivationTime(pDeactivationTime);
795 }
796 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
797 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
798 {
799 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
800 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
801 }
802
803 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
804 {
805 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
806 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
807 }
808
809 public override void ApplyGravity(BulletBody pBody)
810 {
811
812 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
813 body.ApplyGravity();
814 }
815
816 public override Vector3 GetGravity(BulletBody pBody)
817 {
818 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
819 IndexedVector3 gravity = body.GetGravity();
820 return new Vector3(gravity.X, gravity.Y, gravity.Z);
821 }
822
823 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
824 {
825 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
826 float angularDamping = body.GetAngularDamping();
827 body.SetDamping(lin_damping, angularDamping);
828 }
829
830 public override float GetLinearDamping(BulletBody pBody)
831 {
832 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
833 return body.GetLinearDamping();
834 }
835
836 public override float GetAngularDamping(BulletBody pBody)
837 {
838 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
839 return body.GetAngularDamping();
840 }
841
842 public override float GetLinearSleepingThreshold(BulletBody pBody)
843 {
844 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
845 return body.GetLinearSleepingThreshold();
846 }
847
848 public override void ApplyDamping(BulletBody pBody, float timeStep)
849 {
850 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
851 body.ApplyDamping(timeStep);
852 }
853
854 public override Vector3 GetLinearFactor(BulletBody pBody)
855 {
856 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
857 IndexedVector3 linearFactor = body.GetLinearFactor();
858 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
859 }
860
861 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
862 {
863 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
864 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
865 }
866
867 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
868 {
869 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
870 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
871 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
872 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
873 body.SetCenterOfMassTransform( ref mat);
874 /* TODO: double check this */
875 }
876
877 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
878 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
879 {
880 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
881 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
882 body.ApplyCentralForce(ref fSum);
883 }
884 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
885 {
886 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
887 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
888 body.ApplyCentralImpulse(ref fSum);
889 }
890 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
891 {
892 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
893 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
894 body.ApplyTorque(ref fSum);
895 }
896 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
897 {
898 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
899 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
900 body.ApplyTorqueImpulse(ref fSum);
901 }
902
903 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
904 {
905 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
906 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
907 RigidBody bo = co as RigidBody;
908 if (bo == null)
909 {
910
911 if (world.IsInWorld(co))
912 {
913 world.RemoveCollisionObject(co);
914 }
915 }
916 else
917 {
918
919 if (world.IsInWorld(bo))
920 {
921 world.RemoveRigidBody(bo);
922 }
923 }
924 if (co != null)
925 {
926 if (co.GetUserPointer() != null)
927 {
928 uint localId = (uint) co.GetUserPointer();
929 if (specialCollisionObjects.ContainsKey(localId))
930 {
931 specialCollisionObjects.Remove(localId);
932 }
933 }
934 }
935
936 }
937
938 public override void Shutdown(BulletWorld pWorld)
939 {
940 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
941 world.Cleanup();
942 }
943
944 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
945 {
946 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
947
948 // TODO: Turn this from a reference copy to a Value Copy.
949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
950
951 return shape2;
952 }
953
954 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
955 {
956 //TODO:
957 return false;
958 }
959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
960
961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
962 {
963 CollisionWorld world = (pWorld as BulletWorldXNA).world;
964 IndexedMatrix mat =
965 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
966 pRawOrientation.Z, pRawOrientation.W));
967 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
968 CollisionShape shape = (pShape as BulletShapeXNA).shape;
969 //UpdateSingleAabb(world, shape);
970 // TODO: Feed Update array into null
971 SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
972 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
973 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
974 {
975 m_mass = 0
976 };
977 /*
978 m_mass = mass;
979 m_motionState =motionState;
980 m_collisionShape = collisionShape;
981 m_localInertia = localInertia;
982 m_linearDamping = 0f;
983 m_angularDamping = 0f;
984 m_friction = 0.5f;
985 m_restitution = 0f;
986 m_linearSleepingThreshold = 0.8f;
987 m_angularSleepingThreshold = 1f;
988 m_additionalDamping = false;
989 m_additionalDampingFactor = 0.005f;
990 m_additionalLinearDampingThresholdSqr = 0.01f;
991 m_additionalAngularDampingThresholdSqr = 0.01f;
992 m_additionalAngularDampingFactor = 0.01f;
993 m_startWorldTransform = IndexedMatrix.Identity;
994 */
995 body.SetUserPointer(pLocalID);
996
997 return new BulletBodyXNA(pLocalID, body);
998 }
999
1000
1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1002 {
1003
1004 IndexedMatrix mat =
1005 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1006 pRawOrientation.Z, pRawOrientation.W));
1007 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1008
1009 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1010
1011 // TODO: Feed Update array into null
1012 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
1013 body.SetWorldTransform(mat);
1014 body.SetUserPointer(pLocalID);
1015 return new BulletBodyXNA(pLocalID, body);
1016 }
1017 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
1018 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
1019 {
1020 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1021 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
1022 return (CollisionFlags)collisionObject.GetCollisionFlags();
1023 }
1024
1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1026 {
1027
1028 /* TODO */
1029 return Vector3.Zero;
1030 }
1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
1032 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
1033 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
1034 public override bool IsStaticObject(BulletBody pCollisionObject)
1035 {
1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1037 return collisionObject.IsStaticObject();
1038
1039 }
1040 public override bool IsKinematicObject(BulletBody pCollisionObject)
1041 {
1042 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1043 return collisionObject.IsKinematicObject();
1044 }
1045 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1046 {
1047 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1048 return collisionObject.IsStaticOrKinematicObject();
1049 }
1050 public override bool HasContactResponse(BulletBody pCollisionObject)
1051 {
1052 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1053 return collisionObject.HasContactResponse();
1054 }
1055 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1056 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1057 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1058 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1059 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1060 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1061 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1062 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1063
1064 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1065 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1066 {
1067 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1068 collisionObject.SetHitFraction(pHitFraction);
1069 }
1070 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1071 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1072 {
1073 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1074 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1075 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1076 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1077 capsuleShapeZ.SetLocalScaling(ref scale);
1078
1079 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1080 }
1081
1082 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1083 int maxCollisions, ref CollisionDesc[] collisionArray,
1084 int maxUpdates, ref EntityProperties[] updateArray
1085 )
1086 {
1087
1088 UpdatedObjects = updateArray;
1089 UpdatedCollisions = collisionArray;
1090 /* TODO */
1091 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1092 configparms[0] = parms;
1093 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
1094 m_maxCollisions = maxCollisions;
1095 m_maxUpdatesPerFrame = maxUpdates;
1096 specialCollisionObjects = new Dictionary<uint, GhostObject>();
1097
1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1099 }
1100
1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1102 ConfigurationParameters[] o,
1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1105 object mDebugLogCallbackHandle)
1106 {
1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1108
1109 p.angularDamping = BSParam.AngularDamping;
1110 p.defaultFriction = o[0].defaultFriction;
1111 p.defaultFriction = o[0].defaultFriction;
1112 p.defaultDensity = o[0].defaultDensity;
1113 p.defaultRestitution = o[0].defaultRestitution;
1114 p.collisionMargin = o[0].collisionMargin;
1115 p.gravity = o[0].gravity;
1116
1117 p.linearDamping = BSParam.LinearDamping;
1118 p.angularDamping = BSParam.AngularDamping;
1119 p.deactivationTime = BSParam.DeactivationTime;
1120 p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
1121 p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
1122 p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
1123 p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
1124 p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
1125
1126 p.terrainImplementation = BSParam.TerrainImplementation;
1127 p.terrainFriction = BSParam.TerrainFriction;
1128
1129 p.terrainHitFraction = BSParam.TerrainHitFraction;
1130 p.terrainRestitution = BSParam.TerrainRestitution;
1131 p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
1132
1133 p.avatarFriction = BSParam.AvatarFriction;
1134 p.avatarStandingFriction = BSParam.AvatarStandingFriction;
1135 p.avatarDensity = BSParam.AvatarDensity;
1136 p.avatarRestitution = BSParam.AvatarRestitution;
1137 p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1141
1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1143
1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1147 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1148 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1149 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1150 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1151 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1152
1153 p.linksetImplementation = BSParam.LinksetImplementation;
1154 p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
1155 p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
1156 p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
1157 p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
1158 p.linkConstraintERP = BSParam.LinkConstraintERP;
1159 p.linkConstraintCFM = BSParam.LinkConstraintCFM;
1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1163
1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1166
1167
1168 if (p.maxPersistantManifoldPoolSize > 0)
1169 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1170 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1171 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1172 //if (p.maxCollisionAlgorithmPoolSize >0 )
1173
1174 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1175 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1176 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1177
1178 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1179 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1180
1181 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1182
1183 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1184
1185 world.LastCollisionDesc = 0;
1186 world.LastEntityProperty = 0;
1187
1188 world.WorldSettings.Params = p;
1189 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1190 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1191 if (p.shouldRandomizeSolverOrder != 0)
1192 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1193
1194 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1195 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1196
1197 if (p.shouldEnableFrictionCaching != 0)
1198 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1199
1200 if (p.numberOfSolverIterations > 0)
1201 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1202
1203
1204 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1205 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1206 world.GetSolverInfo().m_globalCfm = 0.0f;
1207 world.GetSolverInfo().m_tau = 0.6f;
1208 world.GetSolverInfo().m_friction = 0.3f;
1209 world.GetSolverInfo().m_maxErrorReduction = 20f;
1210 world.GetSolverInfo().m_numIterations = 10;
1211 world.GetSolverInfo().m_erp = 0.2f;
1212 world.GetSolverInfo().m_erp2 = 0.1f;
1213 world.GetSolverInfo().m_sor = 1.0f;
1214 world.GetSolverInfo().m_splitImpulse = false;
1215 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1216 world.GetSolverInfo().m_linearSlop = 0.0f;
1217 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1218 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1219 world.SetForceUpdateAllAabbs(true);
1220
1221 //BSParam.TerrainImplementation = 0;
1222 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1223
1224 return world;
1225 }
1226 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1227 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1228 {
1229 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1230 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1231 {
1232 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1233 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1234 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1235 }
1236 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1237 {
1238 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1239 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1240 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1241 }
1242 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1243 {
1244 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1245 }
1246 return true;
1247 }
1248
1249 public override bool PushUpdate(BulletBody pCollisionObject)
1250 {
1251 bool ret = false;
1252 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1253 RigidBody rb = collisionObject as RigidBody;
1254 if (rb != null)
1255 {
1256 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1257 if (sms != null)
1258 {
1259 IndexedMatrix wt = IndexedMatrix.Identity;
1260 sms.GetWorldTransform(out wt);
1261 sms.SetWorldTransform(ref wt, true);
1262 ret = true;
1263 }
1264 }
1265 return ret;
1266
1267 }
1268
1269 public override float GetAngularMotionDisc(BulletShape pShape)
1270 {
1271 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1272 return shape.GetAngularMotionDisc();
1273 }
1274 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1275 {
1276 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1277 return shape.GetContactBreakingThreshold(defaultFactor);
1278 }
1279 public override bool IsCompound(BulletShape pShape)
1280 {
1281 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1282 return shape.IsCompound();
1283 }
1284 public override bool IsSoftBody(BulletShape pShape)
1285 {
1286 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1287 return shape.IsSoftBody();
1288 }
1289 public override bool IsPolyhedral(BulletShape pShape)
1290 {
1291 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1292 return shape.IsPolyhedral();
1293 }
1294 public override bool IsConvex2d(BulletShape pShape)
1295 {
1296 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1297 return shape.IsConvex2d();
1298 }
1299 public override bool IsConvex(BulletShape pShape)
1300 {
1301 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1302 return shape.IsConvex();
1303 }
1304 public override bool IsNonMoving(BulletShape pShape)
1305 {
1306 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1307 return shape.IsNonMoving();
1308 }
1309 public override bool IsConcave(BulletShape pShape)
1310 {
1311 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1312 return shape.IsConcave();
1313 }
1314 public override bool IsInfinite(BulletShape pShape)
1315 {
1316 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1317 return shape.IsInfinite();
1318 }
1319 public override bool IsNativeShape(BulletShape pShape)
1320 {
1321 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1322 bool ret;
1323 switch (shape.GetShapeType())
1324 {
1325 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1326 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1327 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1328 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1329 ret = true;
1330 break;
1331 default:
1332 ret = false;
1333 break;
1334 }
1335 return ret;
1336 }
1337
1338 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1339 {
1340 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1341 shape.SetMargin(pMargin);
1342 }
1343
1344 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1345 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1346 {
1347 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1348 IndexedMatrix bodyTransform = new IndexedMatrix();
1349 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1350 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1351 GhostObject gObj = new PairCachingGhostObject();
1352 gObj.SetWorldTransform(bodyTransform);
1353 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1354 gObj.SetCollisionShape(shape);
1355 gObj.SetUserPointer(pLocalID);
1356
1357 if (specialCollisionObjects.ContainsKey(pLocalID))
1358 specialCollisionObjects[pLocalID] = gObj;
1359 else
1360 specialCollisionObjects.Add(pLocalID, gObj);
1361
1362 // TODO: Add to Special CollisionObjects!
1363 return new BulletBodyXNA(pLocalID, gObj);
1364 }
1365
1366 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1367 {
1368 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1369 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1370 if (pShape == null)
1371 {
1372 collisionObject.SetCollisionShape(new EmptyShape());
1373 }
1374 else
1375 {
1376 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1377 collisionObject.SetCollisionShape(shape);
1378 }
1379 }
1380 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1381 {
1382 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1383 CollisionShape shape = collisionObject.GetCollisionShape();
1384 return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1385 }
1386
1387 //(PhysicsScene.World.ptr, nativeShapeData)
1388 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1389 {
1390 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1391 CollisionShape shape = null;
1392 switch (pShapeData.Type)
1393 {
1394 case BSPhysicsShapeType.SHAPE_BOX:
1395 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1396 break;
1397 case BSPhysicsShapeType.SHAPE_CONE:
1398 shape = new ConeShapeZ(0.5f, 1.0f);
1399 break;
1400 case BSPhysicsShapeType.SHAPE_CYLINDER:
1401 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1402 break;
1403 case BSPhysicsShapeType.SHAPE_SPHERE:
1404 shape = new SphereShape(0.5f);
1405 break;
1406
1407 }
1408 if (shape != null)
1409 {
1410 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1411 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1412 shape.SetLocalScaling(ref scaling);
1413
1414 }
1415 return new BulletShapeXNA(shape, pShapeData.Type);
1416 }
1417 //PhysicsScene.World.ptr, false
1418 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1419 {
1420 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1421 }
1422
1423 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1424 {
1425 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1426 return compoundshape.GetNumChildShapes();
1427 }
1428 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1429 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1430 {
1431 IndexedMatrix relativeTransform = new IndexedMatrix();
1432 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1433 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1434
1435 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1436 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1437 compoundshape.AddChildShape(ref relativeTransform, addshape);
1438
1439 }
1440
1441 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1442 {
1443 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1444 CollisionShape ret = null;
1445 ret = compoundshape.GetChildShape(pii);
1446 compoundshape.RemoveChildShapeByIndex(pii);
1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1448 }
1449
1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1451
1452 if (cShape == null)
1453 return null;
1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
1455 CollisionShape shape = compoundShape.GetChildShape(indx);
1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1457
1458
1459 return retShape;
1460 }
1461
1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
1463 {
1464 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1465 switch (pin)
1466 {
1467 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1468 ret = BSPhysicsShapeType.SHAPE_BOX;
1469 break;
1470 case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
1471 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1472 break;
1473
1474 case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
1475 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1476 break;
1477 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1478 ret = BSPhysicsShapeType.SHAPE_MESH;
1479 break;
1480 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1481 ret = BSPhysicsShapeType.SHAPE_HULL;
1482 break;
1483 case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
1484 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1485 break;
1486 case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
1487 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1488 break;
1489 //implicit convex shapes
1490 case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
1491 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1492 break;
1493 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1494 ret = BSPhysicsShapeType.SHAPE_SPHERE;
1495 break;
1496 case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
1497 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1498 break;
1499 case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
1500 ret = BSPhysicsShapeType.SHAPE_CAPSULE;
1501 break;
1502 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1503 ret = BSPhysicsShapeType.SHAPE_CONE;
1504 break;
1505 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1506 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1507 break;
1508 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1509 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
1510 break;
1511 case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
1512 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1513 break;
1514 case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
1515 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1516 break;
1517 case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
1518 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1519 break;
1520 case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
1521 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1522 break;
1523 case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
1524 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1525 break;
1526 case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
1527 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1528 break;
1529 //concave shape
1530 case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
1531 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1532 break;
1533 //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
1534 case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
1535 ret = BSPhysicsShapeType.SHAPE_MESH;
1536 break;
1537 case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
1538 ret = BSPhysicsShapeType.SHAPE_MESH;
1539 break;
1540 ///used for demo integration FAST/Swift collision library and Bullet
1541 case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
1542 ret = BSPhysicsShapeType.SHAPE_MESH;
1543 break;
1544 //terrain
1545 case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
1546 ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
1547 break;
1548 ///Used for GIMPACT Trimesh integration
1549 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1550 ret = BSPhysicsShapeType.SHAPE_MESH;
1551 break;
1552 ///Multimaterial mesh
1553 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
1554 ret = BSPhysicsShapeType.SHAPE_MESH;
1555 break;
1556
1557 case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
1558 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1559 break;
1560 case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
1561 ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
1562 break;
1563 case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
1564 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1565 break;
1566 case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
1567 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1568 break;
1569
1570 case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
1571 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
1572 break;
1573
1574 case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
1575 ret = BSPhysicsShapeType.SHAPE_MESH;
1576 break;
1577 case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
1578 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1579 break;
1580 case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
1581 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1582 break;
1583 case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
1584 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1585 break;
1586 }
1587 return ret;
1588 }
1589
1590 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1591 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1592
1593 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1594 {
1595 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1596 m_planeshape.SetMargin(pcollisionMargin);
1597 m_planeshape.SetUserPointer(pLocalId);
1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1599 }
1600
1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1604
1605 {
1606 Generic6DofSpringConstraint constrain = null;
1607 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1608 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
1609 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
1610 if (body1 != null && body2 != null)
1611 {
1612 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1613 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1614 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1615 frame1._origin = frame1v;
1616
1617 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1618 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1619 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1620 frame2._origin = frame1v;
1621
1622 constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1623 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1624
1625 constrain.CalculateTransforms();
1626 }
1627
1628 return new BulletConstraintXNA(constrain);
1629 }
1630
1631 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1632 Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
1633 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1634 {
1635 HingeConstraint constrain = null;
1636 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1637 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1638 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1639 if (rb1 != null && rb2 != null)
1640 {
1641 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1642 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1643 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1644 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1645 constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
1646 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1647 }
1648 return new BulletConstraintXNA(constrain);
1649 }
1650
1651 public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1652 Vector3 pframe1, Quaternion pframe1rot,
1653 Vector3 pframe2, Quaternion pframe2rot,
1654 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1655 {
1656 SliderConstraint constrain = null;
1657 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1658 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1659 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1660 if (rb1 != null && rb2 != null)
1661 {
1662 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1663 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1664 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1665 frame1._origin = frame1v;
1666
1667 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1668 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1669 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1670 frame2._origin = frame1v;
1671
1672 constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1673 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1674 }
1675 return new BulletConstraintXNA(constrain);
1676 }
1677
1678 public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1679 Vector3 pframe1, Quaternion pframe1rot,
1680 Vector3 pframe2, Quaternion pframe2rot,
1681 bool pdisableCollisionsBetweenLinkedBodies)
1682 {
1683 ConeTwistConstraint constrain = null;
1684 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1685 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1686 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1687 if (rb1 != null && rb2 != null)
1688 {
1689 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1690 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1691 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1692 frame1._origin = frame1v;
1693
1694 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1695 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1696 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1697 frame2._origin = frame1v;
1698
1699 constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
1700 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1701 }
1702 return new BulletConstraintXNA(constrain);
1703 }
1704
1705 public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1706 Vector3 paxisInA, Vector3 paxisInB,
1707 float pratio, bool pdisableCollisionsBetweenLinkedBodies)
1708 {
1709 Generic6DofConstraint constrain = null;
1710 /* BulletXNA does not have a gear constraint
1711 GearConstraint constrain = null;
1712 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1713 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1714 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1715 if (rb1 != null && rb2 != null)
1716 {
1717 IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1718 IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1719 constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
1720 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1721 }
1722 */
1723 return new BulletConstraintXNA(constrain);
1724 }
1725
1726 public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1727 Vector3 ppivotInA, Vector3 ppivotInB,
1728 bool pdisableCollisionsBetweenLinkedBodies)
1729 {
1730 Point2PointConstraint constrain = null;
1731 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1732 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1733 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1734 if (rb1 != null && rb2 != null)
1735 {
1736 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1737 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1738 constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
1739 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1740 }
1741 return new BulletConstraintXNA(constrain);
1742 }
1743
1744 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1745 {
1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1747 CompoundShape compoundshape = new CompoundShape(false);
1748
1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1750 int ii = 1;
1751
1752 for (int i = 0; i < pHullCount; i++)
1753 {
1754 int vertexCount = (int) pConvHulls[ii];
1755
1756 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1757 IndexedMatrix childTrans = IndexedMatrix.Identity;
1758 childTrans._origin = centroid;
1759
1760 List<IndexedVector3> virts = new List<IndexedVector3>();
1761 int ender = ((ii + 4) + (vertexCount*3));
1762 for (int iii = ii + 4; iii < ender; iii+=3)
1763 {
1764
1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1766 }
1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1768 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1769 compoundshape.AddChildShape(ref childTrans, convexShape);
1770 ii += (vertexCount*3 + 4);
1771 }
1772
1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1774 }
1775
1776 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
1777 {
1778 /* TODO */ return null;
1779
1780 }
1781
1782 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1783 {
1784 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1785
1786 for (int iter = 0; iter < pVerticesCount; iter++)
1787 {
1788 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1789 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1790 }
1791
1792 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1793 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1794 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1795 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1796 IndexedMesh mesh = new IndexedMesh();
1797 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1798 mesh.m_numTriangles = pIndicesCount/3;
1799 mesh.m_numVertices = pVerticesCount;
1800 mesh.m_triangleIndexBase = indicesarr;
1801 mesh.m_vertexBase = vertices;
1802 mesh.m_vertexStride = 3;
1803 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1804 mesh.m_triangleIndexStride = 3;
1805
1806 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1807 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1808 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1809 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1810 // world.UpdateSingleAabb(meshShape);
1811 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1812
1813 }
1814 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1815 {
1816
1817 String fileName = "objTest3.raw";
1818 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1819 StreamWriter sw = new StreamWriter(completePath);
1820 IndexedMesh mesh = new IndexedMesh();
1821
1822 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1823 mesh.m_numTriangles = pIndicesCount / 3;
1824 mesh.m_numVertices = pVerticesCount;
1825 mesh.m_triangleIndexBase = indices;
1826 mesh.m_vertexBase = vertices;
1827 mesh.m_vertexStride = 3;
1828 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1829 mesh.m_triangleIndexStride = 3;
1830
1831 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1832 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1833
1834
1835
1836 for (int i = 0; i < pVerticesCount; i++)
1837 {
1838
1839 string s = vertices[indices[i * 3]].ToString("0.0000");
1840 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1841 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1842
1843 sw.Write(s + "\n");
1844 }
1845
1846 sw.Close();
1847 }
1848 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1849 {
1850
1851 String fileName = "objTest6.raw";
1852 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1853 StreamWriter sw = new StreamWriter(completePath);
1854 IndexedMesh mesh = new IndexedMesh();
1855
1856 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1857 mesh.m_numTriangles = pIndicesCount / 3;
1858 mesh.m_numVertices = pVerticesCount;
1859 mesh.m_triangleIndexBase = indices;
1860 mesh.m_vertexBase = vertices;
1861 mesh.m_vertexStride = 3;
1862 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1863 mesh.m_triangleIndexStride = 3;
1864
1865 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1866 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1867
1868
1869 sw.WriteLine("Indices");
1870 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1871 for (int iter = 0; iter < indices.Length; iter++)
1872 {
1873 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1874 }
1875 sw.WriteLine("VerticesFloats");
1876 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1877 for (int iter = 0; iter < vertices.Length; iter++)
1878 {
1879 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1880 }
1881
1882 // for (int i = 0; i < pVerticesCount; i++)
1883 // {
1884 //
1885 // string s = vertices[indices[i * 3]].ToString("0.0000");
1886 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1887 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1888 //
1889 // sw.Write(s + "\n");
1890 //}
1891
1892 sw.Close();
1893 }
1894
1895 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1896 float scaleFactor, float collisionMargin)
1897 {
1898 const int upAxis = 2;
1899 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1900 heightMap, scaleFactor,
1901 minHeight, maxHeight, upAxis,
1902 false);
1903 terrainShape.SetMargin(collisionMargin + 0.5f);
1904 terrainShape.SetUseDiamondSubdivision(true);
1905 terrainShape.SetUserPointer(id);
1906 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1907 }
1908
1909 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1910 {
1911 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
1912 bool onOff = ponOff != 0;
1913 bool ret = false;
1914
1915 switch (tconstrain.GetConstraintType())
1916 {
1917 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1918 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1919 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1920 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1921 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1922 ret = true;
1923 break;
1924 }
1925
1926
1927 return ret;
1928
1929 }
1930
1931 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1932 out int updatedEntityCount, out int collidersCount)
1933 {
1934 /* TODO */
1935 updatedEntityCount = 0;
1936 collidersCount = 0;
1937
1938
1939 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1940
1941 return ret;
1942 }
1943
1944 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1945 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1946 out int collidersCount, out CollisionDesc[] colliders)
1947 {
1948 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1949 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
1950 return epic;
1951 }
1952
1953 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1954 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1955 {
1956 int numSimSteps = 0;
1957 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
1958 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
1959 LastEntityProperty=0;
1960
1961
1962
1963
1964
1965
1966 LastCollisionDesc=0;
1967
1968 updatedEntityCount = 0;
1969 collidersCount = 0;
1970
1971
1972 if (pWorld is BulletWorldXNA)
1973 {
1974 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1975
1976 world.LastCollisionDesc = 0;
1977 world.LastEntityProperty = 0;
1978 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1979 int updates = 0;
1980
1981 PersistentManifold contactManifold;
1982 CollisionObject objA;
1983 CollisionObject objB;
1984 ManifoldPoint manifoldPoint;
1985 PairCachingGhostObject pairCachingGhostObject;
1986
1987 m_collisionsThisFrame = 0;
1988 int numManifolds = world.GetDispatcher().GetNumManifolds();
1989 for (int j = 0; j < numManifolds; j++)
1990 {
1991 contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1992 int numContacts = contactManifold.GetNumContacts();
1993 if (numContacts == 0)
1994 continue;
1995
1996 objA = contactManifold.GetBody0() as CollisionObject;
1997 objB = contactManifold.GetBody1() as CollisionObject;
1998
1999 manifoldPoint = contactManifold.GetContactPoint(0);
2000 //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
2001 // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
2002
2003 RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
2004 m_collisionsThisFrame ++;
2005 if (m_collisionsThisFrame >= 9999999)
2006 break;
2007
2008
2009 }
2010
2011 foreach (GhostObject ghostObject in specialCollisionObjects.Values)
2012 {
2013 pairCachingGhostObject = ghostObject as PairCachingGhostObject;
2014 if (pairCachingGhostObject != null)
2015 {
2016 RecordGhostCollisions(pairCachingGhostObject);
2017 }
2018
2019 }
2020
2021
2022 updatedEntityCount = LastEntityProperty;
2023 updatedEntities = UpdatedObjects;
2024
2025 collidersCount = LastCollisionDesc;
2026 colliders = UpdatedCollisions;
2027
2028
2029 }
2030 else
2031 {
2032 //if (updatedEntities is null)
2033 //updatedEntities = new List<BulletXNA.EntityProperties>();
2034 //updatedEntityCount = 0;
2035
2036
2037 //collidersCount = 0;
2038
2039 updatedEntities = new EntityProperties[0];
2040
2041
2042 colliders = new CollisionDesc[0];
2043
2044 }
2045 return numSimSteps;
2046 }
2047 public void RecordGhostCollisions(PairCachingGhostObject obj)
2048 {
2049 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2050 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2051
2052 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2053 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2054 BroadphasePair collisionPair;
2055 PersistentManifold contactManifold;
2056
2057 CollisionObject objA;
2058 CollisionObject objB;
2059
2060 ManifoldPoint pt;
2061
2062 int numPairs = pairs.Count;
2063
2064 for (int i = 0; i < numPairs; i++)
2065 {
2066 manifoldArray.Clear();
2067 if (LastCollisionDesc < UpdatedCollisions.Length)
2068 break;
2069 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2070 if (collisionPair == null)
2071 continue;
2072
2073 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2074 for (int j = 0; j < manifoldArray.Count; j++)
2075 {
2076 contactManifold = manifoldArray[j];
2077 int numContacts = contactManifold.GetNumContacts();
2078 objA = contactManifold.GetBody0() as CollisionObject;
2079 objB = contactManifold.GetBody1() as CollisionObject;
2080 for (int p = 0; p < numContacts; p++)
2081 {
2082 pt = contactManifold.GetContactPoint(p);
2083 if (pt.GetDistance() < 0.0f)
2084 {
2085 RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
2086 break;
2087 }
2088 }
2089 }
2090 }
2091
2092 }
2093 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2094 {
2095
2096 IndexedVector3 contactNormal = norm;
2097 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2098 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
2099 {
2100 return;
2101 }
2102 uint idA = (uint)objA.GetUserPointer();
2103 uint idB = (uint)objB.GetUserPointer();
2104 if (idA > idB)
2105 {
2106 uint temp = idA;
2107 idA = idB;
2108 idB = temp;
2109 contactNormal = -contactNormal;
2110 }
2111
2112 //ulong collisionID = ((ulong) idA << 32) | idB;
2113
2114 CollisionDesc cDesc = new CollisionDesc()
2115 {
2116 aID = idA,
2117 bID = idB,
2118 point = new Vector3(contact.X,contact.Y,contact.Z),
2119 normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
2120 penetration = penetration
2121
2122 };
2123 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
2124 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
2125 m_collisionsThisFrame++;
2126
2127
2128 }
2129 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
2130 {
2131 EntityProperties ent = new EntityProperties();
2132 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2133 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
2134 IndexedMatrix transform = collisionObject.GetWorldTransform();
2135 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
2136 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
2137 IndexedQuaternion rotation = transform.GetRotation();
2138 ent.Acceleration = Vector3.Zero;
2139 ent.ID = (uint)collisionObject.GetUserPointer();
2140 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
2141 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
2142 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
2143 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
2144 return ent;
2145 }
2146
2147 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
2148 return false; }
2149
2150 public override Vector3 GetLocalScaling(BulletShape pShape)
2151 {
2152 CollisionShape shape = (pShape as BulletShapeXNA).shape;
2153 IndexedVector3 scale = shape.GetLocalScaling();
2154 return new Vector3(scale.X,scale.Y,scale.Z);
2155 }
2156
2157 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
2158 {
2159 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2160 if (world != null)
2161 {
2162 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2163 {
2164 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2165
2166 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2167 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2168 using (
2169 ClosestNotMeRayResultCallback rayCallback =
2170 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2171 )
2172 {
2173 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
2174 if (rayCallback.HasHit())
2175 {
2176 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
2177 }
2178 return rayCallback.HasHit();
2179 }
2180 }
2181 }
2182 return false;
2183 }
2184}
2185
2186
2187
2188
2189 public class SimMotionState : DefaultMotionState
2190 {
2191 public RigidBody Rigidbody;
2192 public Vector3 ZeroVect;
2193
2194 private IndexedMatrix m_xform;
2195
2196 private EntityProperties m_properties;
2197 private EntityProperties m_lastProperties;
2198 private BSAPIXNA m_world;
2199
2200 const float POSITION_TOLERANCE = 0.05f;
2201 const float VELOCITY_TOLERANCE = 0.001f;
2202 const float ROTATION_TOLERANCE = 0.01f;
2203 const float ANGULARVELOCITY_TOLERANCE = 0.01f;
2204
2205 public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
2206 {
2207 IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
2208 m_properties = new EntityProperties()
2209 {
2210 ID = id,
2211 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
2212 Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
2213 };
2214 m_lastProperties = new EntityProperties()
2215 {
2216 ID = id,
2217 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
2218 Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
2219 };
2220 m_world = pWorld;
2221 m_xform = starTransform;
2222 }
2223
2224 public override void GetWorldTransform(out IndexedMatrix worldTrans)
2225 {
2226 worldTrans = m_xform;
2227 }
2228
2229 public override void SetWorldTransform(IndexedMatrix worldTrans)
2230 {
2231 SetWorldTransform(ref worldTrans);
2232 }
2233
2234 public override void SetWorldTransform(ref IndexedMatrix worldTrans)
2235 {
2236 SetWorldTransform(ref worldTrans, false);
2237 }
2238 public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
2239 {
2240 m_xform = worldTrans;
2241 // Put the new transform into m_properties
2242 IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
2243 IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
2244 IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
2245 m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
2246 m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
2247 OrientationQuaternion.Z, OrientationQuaternion.W);
2248 // A problem with stock Bullet is that we don't get an event when an object is deactivated.
2249 // This means that the last non-zero values for linear and angular velocity
2250 // are left in the viewer who does dead reconning and the objects look like
2251 // they float off.
2252 // BulletSim ships with a patch to Bullet which creates such an event.
2253 m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
2254 m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
2255
2256 if (force
2257
2258 || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
2259 || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
2260 // If the Velocity and AngularVelocity are zero, most likely the object has
2261 // been deactivated. If they both are zero and they have become zero recently,
2262 // make sure a property update is sent so the zeros make it to the viewer.
2263 || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
2264 &&
2265 (m_properties.Velocity != m_lastProperties.Velocity ||
2266 m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
2267 // If Velocity and AngularVelocity are non-zero but have changed, send an update.
2268 || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
2269 ||
2270 !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
2271 ANGULARVELOCITY_TOLERANCE)
2272 )
2273
2274
2275 {
2276 // Add this update to the list of updates for this frame.
2277 m_lastProperties = m_properties;
2278 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2279 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2280
2281 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2282 }
2283
2284
2285
2286
2287 }
2288 public override void SetRigidBody(RigidBody body)
2289 {
2290 Rigidbody = body;
2291 }
2292 internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
2293 {
2294 return
2295 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2296 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2297 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
2298 }
2299
2300 internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
2301 {
2302 return
2303 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2304 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2305 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2306 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2307 }
2308
2309 }
2310}
2311
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
new file mode 100644
index 0000000..5765b0d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -0,0 +1,683 @@
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 UInt32 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 UInt32 ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public UInt32 ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public UInt32 aID;
130 public UInt32 bID;
131 public Vector3 point;
132 public Vector3 normal;
133 public float penetration;
134}
135[StructLayout(LayoutKind.Sequential)]
136public struct EntityProperties
137{
138 public UInt32 ID;
139 public Vector3 Position;
140 public Quaternion Rotation;
141 public Vector3 Velocity;
142 public Vector3 Acceleration;
143 public Vector3 RotationalVelocity;
144
145 public override string ToString()
146 {
147 StringBuilder buff = new StringBuilder();
148 buff.Append("<i=");
149 buff.Append(ID.ToString());
150 buff.Append(",p=");
151 buff.Append(Position.ToString());
152 buff.Append(",r=");
153 buff.Append(Rotation.ToString());
154 buff.Append(",v=");
155 buff.Append(Velocity.ToString());
156 buff.Append(",a=");
157 buff.Append(Acceleration.ToString());
158 buff.Append(",rv=");
159 buff.Append(RotationalVelocity.ToString());
160 buff.Append(">");
161 return buff.ToString();
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 maxPersistantManifoldPoolSize;
178 public float maxCollisionAlgorithmPoolSize;
179 public float shouldDisableContactPoolDynamicAllocation;
180 public float shouldForceUpdateAllAabbs;
181 public float shouldRandomizeSolverOrder;
182 public float shouldSplitSimulationIslands;
183 public float shouldEnableFrictionCaching;
184 public float numberOfSolverIterations;
185 public float useSingleSidedMeshes;
186 public float globalContactBreakingThreshold;
187
188 public float physicsLoggingFrames;
189
190 public const float numericTrue = 1f;
191 public const float numericFalse = 0f;
192}
193
194
195// The states a bullet collision object can have
196public enum ActivationState : uint
197{
198 ACTIVE_TAG = 1,
199 ISLAND_SLEEPING,
200 WANTS_DEACTIVATION,
201 DISABLE_DEACTIVATION,
202 DISABLE_SIMULATION,
203}
204
205public enum CollisionObjectTypes : int
206{
207 CO_COLLISION_OBJECT = 1 << 0,
208 CO_RIGID_BODY = 1 << 1,
209 CO_GHOST_OBJECT = 1 << 2,
210 CO_SOFT_BODY = 1 << 3,
211 CO_HF_FLUID = 1 << 4,
212 CO_USER_TYPE = 1 << 5,
213}
214
215// Values used by Bullet and BulletSim to control object properties.
216// Bullet's "CollisionFlags" has more to do with operations on the
217// object (if collisions happen, if gravity effects it, ...).
218public enum CollisionFlags : uint
219{
220 CF_STATIC_OBJECT = 1 << 0,
221 CF_KINEMATIC_OBJECT = 1 << 1,
222 CF_NO_CONTACT_RESPONSE = 1 << 2,
223 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
224 CF_CHARACTER_OBJECT = 1 << 4,
225 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
226 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
227 // Following used by BulletSim to control collisions and updates
228 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
229 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
230 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
231 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
232 BS_NONE = 0,
233 BS_ALL = 0xFFFFFFFF
234};
235
236// Values f collisions groups and masks
237public enum CollisionFilterGroups : uint
238{
239 // Don't use the bit definitions!! Define the use in a
240 // filter/mask definition below. This way collision interactions
241 // are more easily found and debugged.
242 BNoneGroup = 0,
243 BDefaultGroup = 1 << 0, // 0001
244 BStaticGroup = 1 << 1, // 0002
245 BKinematicGroup = 1 << 2, // 0004
246 BDebrisGroup = 1 << 3, // 0008
247 BSensorTrigger = 1 << 4, // 0010
248 BCharacterGroup = 1 << 5, // 0020
249 BAllGroup = 0x000FFFFF,
250 // Filter groups defined by BulletSim
251 BGroundPlaneGroup = 1 << 10, // 0400
252 BTerrainGroup = 1 << 11, // 0800
253 BRaycastGroup = 1 << 12, // 1000
254 BSolidGroup = 1 << 13, // 2000
255 // BLinksetGroup = xx // a linkset proper is either static or dynamic
256 BLinksetChildGroup = 1 << 14, // 4000
257};
258
259// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
260// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
261public enum ConstraintParams : int
262{
263 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
264 BT_CONSTRAINT_STOP_ERP,
265 BT_CONSTRAINT_CFM,
266 BT_CONSTRAINT_STOP_CFM,
267};
268public enum ConstraintParamAxis : int
269{
270 AXIS_LINEAR_X = 0,
271 AXIS_LINEAR_Y,
272 AXIS_LINEAR_Z,
273 AXIS_ANGULAR_X,
274 AXIS_ANGULAR_Y,
275 AXIS_ANGULAR_Z,
276 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
277 AXIS_ANGULAR_ALL,
278 AXIS_ALL
279};
280
281public abstract class BSAPITemplate
282{
283// Returns the name of the underlying Bullet engine
284public abstract string BulletEngineName { get; }
285public abstract string BulletEngineVersion { get; protected set;}
286
287// Initialization and simulation
288public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
289 int maxCollisions, ref CollisionDesc[] collisionArray,
290 int maxUpdates, ref EntityProperties[] updateArray
291 );
292
293public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
294 out int updatedEntityCount, out int collidersCount);
295
296public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
297
298public abstract void Shutdown(BulletWorld sim);
299
300public abstract bool PushUpdate(BulletBody obj);
301
302// =====================================================================================
303// Mesh, hull, shape and body creation helper routines
304public abstract BulletShape CreateMeshShape(BulletWorld world,
305 int indicesCount, int[] indices,
306 int verticesCount, float[] vertices );
307
308public abstract BulletShape CreateHullShape(BulletWorld world,
309 int hullCount, float[] hulls);
310
311public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
312
313public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
314
315public abstract bool IsNativeShape(BulletShape shape);
316
317public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
318
319public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
320
321public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
322
323public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
324
325public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
326
327public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
328
329public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
330
331public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
332
333public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
334
335public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
336
337public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
338
339public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
340
341public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
342
343public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
344
345public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
346
347public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
348
349public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
350
351// =====================================================================================
352public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
353
354public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
355 float scaleFactor, float collisionMargin);
356
357// =====================================================================================
358// Constraint creation and helper routines
359public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
360 Vector3 frame1loc, Quaternion frame1rot,
361 Vector3 frame2loc, Quaternion frame2rot,
362 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
363
364public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
365 Vector3 joinPoint,
366 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
367
368public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
369 Vector3 frameInBloc, Quaternion frameInBrot,
370 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
371
372public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
373 Vector3 frame1loc, Quaternion frame1rot,
374 Vector3 frame2loc, Quaternion frame2rot,
375 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
376
377public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
378 Vector3 pivotinA, Vector3 pivotinB,
379 Vector3 axisInA, Vector3 axisInB,
380 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
381
382public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
383 Vector3 frameInAloc, Quaternion frameInArot,
384 Vector3 frameInBloc, Quaternion frameInBrot,
385 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
386
387public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
388 Vector3 frameInAloc, Quaternion frameInArot,
389 Vector3 frameInBloc, Quaternion frameInBrot,
390 bool disableCollisionsBetweenLinkedBodies);
391
392public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
393 Vector3 axisInA, Vector3 axisInB,
394 float ratio, bool disableCollisionsBetweenLinkedBodies);
395
396public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
397 Vector3 pivotInA, Vector3 pivotInB,
398 bool disableCollisionsBetweenLinkedBodies);
399
400public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
401
402public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
403
404public abstract bool SetFrames(BulletConstraint constrain,
405 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
406
407public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
408
409public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
410
411public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
412
413public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
414
415public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
416
417public abstract bool CalculateTransforms(BulletConstraint constrain);
418
419public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
420
421public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
422
423// =====================================================================================
424// btCollisionWorld entries
425public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
426
427public abstract void UpdateAabbs(BulletWorld world);
428
429public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
430
431public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
432
433// =====================================================================================
434// btDynamicsWorld entries
435// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
436public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
437
438public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
439
440public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
441
442public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
443// =====================================================================================
444// btCollisionObject entries
445public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
446
447public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
448
449public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
450
451public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
452
453public abstract float GetContactProcessingThreshold(BulletBody obj);
454
455public abstract bool IsStaticObject(BulletBody obj);
456
457public abstract bool IsKinematicObject(BulletBody obj);
458
459public abstract bool IsStaticOrKinematicObject(BulletBody obj);
460
461public abstract bool HasContactResponse(BulletBody obj);
462
463public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
464
465public abstract BulletShape GetCollisionShape(BulletBody obj);
466
467public abstract int GetActivationState(BulletBody obj);
468
469public abstract void SetActivationState(BulletBody obj, int state);
470
471public abstract void SetDeactivationTime(BulletBody obj, float dtime);
472
473public abstract float GetDeactivationTime(BulletBody obj);
474
475public abstract void ForceActivationState(BulletBody obj, ActivationState state);
476
477public abstract void Activate(BulletBody obj, bool forceActivation);
478
479public abstract bool IsActive(BulletBody obj);
480
481public abstract void SetRestitution(BulletBody obj, float val);
482
483public abstract float GetRestitution(BulletBody obj);
484
485public abstract void SetFriction(BulletBody obj, float val);
486
487public abstract float GetFriction(BulletBody obj);
488
489public abstract Vector3 GetPosition(BulletBody obj);
490
491public abstract Quaternion GetOrientation(BulletBody obj);
492
493public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
494
495// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
496
497// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
498
499public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
500
501public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
502
503public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
504
505public abstract float GetHitFraction(BulletBody obj);
506
507public abstract void SetHitFraction(BulletBody obj, float val);
508
509public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
510
511public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
512
513public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
514
515public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
516
517public abstract float GetCcdMotionThreshold(BulletBody obj);
518
519public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
520
521public abstract float GetCcdSweptSphereRadius(BulletBody obj);
522
523public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
524
525public abstract IntPtr GetUserPointer(BulletBody obj);
526
527public abstract void SetUserPointer(BulletBody obj, IntPtr val);
528
529// =====================================================================================
530// btRigidBody entries
531public abstract void ApplyGravity(BulletBody obj);
532
533public abstract void SetGravity(BulletBody obj, Vector3 val);
534
535public abstract Vector3 GetGravity(BulletBody obj);
536
537public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
538
539public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
540
541public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
542
543public abstract float GetLinearDamping(BulletBody obj);
544
545public abstract float GetAngularDamping(BulletBody obj);
546
547public abstract float GetLinearSleepingThreshold(BulletBody obj);
548
549public abstract void ApplyDamping(BulletBody obj, float timeStep);
550
551public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
552
553public abstract Vector3 GetLinearFactor(BulletBody obj);
554
555public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
556
557public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
558
559// Add a force to the object as if its mass is one.
560public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
561
562// Set the force being applied to the object as if its mass is one.
563public abstract void SetObjectForce(BulletBody obj, Vector3 force);
564
565public abstract Vector3 GetTotalForce(BulletBody obj);
566
567public abstract Vector3 GetTotalTorque(BulletBody obj);
568
569public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
570
571public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
572
573public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
574
575public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
576
577// Apply force at the given point. Will add torque to the object.
578public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
579
580// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
581public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
582
583// Apply impulse to the object's torque. Force is scaled by object's mass.
584public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
585
586// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
587public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
588
589public abstract void ClearForces(BulletBody obj);
590
591public abstract void ClearAllForces(BulletBody obj);
592
593public abstract void UpdateInertiaTensor(BulletBody obj);
594
595public abstract Vector3 GetLinearVelocity(BulletBody obj);
596
597public abstract Vector3 GetAngularVelocity(BulletBody obj);
598
599public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
600
601public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
602
603public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
604
605public abstract void Translate(BulletBody obj, Vector3 trans);
606
607public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
608
609public abstract bool WantsSleeping(BulletBody obj);
610
611public abstract void SetAngularFactor(BulletBody obj, float factor);
612
613public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
614
615public abstract Vector3 GetAngularFactor(BulletBody obj);
616
617public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
618
619public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
620
621public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
622
623public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
624
625public abstract int GetNumConstraintRefs(BulletBody obj);
626
627public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
628
629// =====================================================================================
630// btCollisionShape entries
631
632public abstract float GetAngularMotionDisc(BulletShape shape);
633
634public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
635
636public abstract bool IsPolyhedral(BulletShape shape);
637
638public abstract bool IsConvex2d(BulletShape shape);
639
640public abstract bool IsConvex(BulletShape shape);
641
642public abstract bool IsNonMoving(BulletShape shape);
643
644public abstract bool IsConcave(BulletShape shape);
645
646public abstract bool IsCompound(BulletShape shape);
647
648public abstract bool IsSoftBody(BulletShape shape);
649
650public abstract bool IsInfinite(BulletShape shape);
651
652public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
653
654public abstract Vector3 GetLocalScaling(BulletShape shape);
655
656public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
657
658public abstract int GetShapeType(BulletShape shape);
659
660public abstract void SetMargin(BulletShape shape, float val);
661
662public abstract float GetMargin(BulletShape shape);
663
664// =====================================================================================
665// Debugging
666public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
667
668public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
669
670public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
671
672public virtual void DumpActivationInfo(BulletWorld sim) { }
673
674public virtual void DumpAllInfo(BulletWorld sim) { }
675
676public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
677
678public virtual void ResetBroadphasePool(BulletWorld sim) { }
679
680public virtual void ResetConstraintSolver(BulletWorld sim) { }
681
682};
683}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..90c2d9c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -45,7 +45,6 @@ public sealed class BSCharacter : BSPhysObject
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position; 46 private OMV.Vector3 _position;
47 private float _mass; 47 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume; 48 private float _avatarVolume;
50 private OMV.Vector3 _force; 49 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity; 50 private OMV.Vector3 _velocity;
@@ -58,16 +57,12 @@ public sealed class BSCharacter : BSPhysObject
58 private bool _flying; 57 private bool _flying;
59 private bool _setAlwaysRun; 58 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 59 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 60 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 61 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 62 private bool _kinematic;
66 private float _buoyancy; 63 private float _buoyancy;
67 64
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 65 private BSVMotor _velocityMotor;
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 66
72 private OMV.Vector3 _PIDTarget; 67 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 68 private bool _usePID;
@@ -83,34 +78,36 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 78 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 79 _position = pos;
85 80
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; 81 _flying = isFlying;
93 _orientation = OMV.Quaternion.Identity; 82 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 83 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 84 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 85 Friction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 86 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
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;
99 93
100 // The dimensions of the avatar capsule are kept in the scale. 94 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 95 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 96 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 98 ComputeAvatarVolumeAndMass();
99
100 SetupMovementMotor();
101
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 102 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 103 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
107 104
108 // do actual create at taint time 105 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 106 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 107 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 108 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 109 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 110 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 111
115 SetPhysicalProperties(); 112 SetPhysicalProperties();
116 }); 113 });
@@ -120,54 +117,216 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 117 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 118 public override void Destroy()
122 { 119 {
120 base.Destroy();
121
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 122 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 123 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 124 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 125 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 126 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */);
128 PhysShape.Clear();
128 }); 129 });
129 } 130 }
130 131
131 private void SetPhysicalProperties() 132 private void SetPhysicalProperties()
132 { 133 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 134 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 135
135 ZeroMotion(true); 136 ZeroMotion(true);
136 ForcePosition = _position; 137 ForcePosition = _position;
137 // Set the velocity and compute the proper friction 138
139 // Set the velocity
140 _velocityMotor.Reset();
141 _velocityMotor.SetTarget(_velocity);
142 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 143 ForceVelocity = _velocity;
139 144
140 // This will enable or disable the flying buoyancy of the avatar. 145 // 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. 146 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 147 Flying = _flying;
143 148
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 149 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 150 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 151 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 152 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 153 if (BSParam.CcdMotionThreshold > 0f)
149 { 154 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 155 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 156 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 157 }
153 158
154 UpdatePhysicalMassProperties(RawMass); 159 UpdatePhysicalMassProperties(RawMass, false);
155 160
156 // Make so capsule does not fall over 161 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 162 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 163
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 164 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 165
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 166 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 167
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 168 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 169 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 170 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 171
167 // Do this after the object has been added to the world 172 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 173 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 174 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 175 }
176
177 // The avatar's movement is controlled by this motor that speeds up and slows down
178 // the avatar seeking to reach the motor's target speed.
179 // This motor runs as a prestep action for the avatar so it will keep the avatar
180 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
181 private void SetupMovementMotor()
182 {
183 // Infinite decay and timescale values so motor only changes current to target values.
184 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
185 0.2f, // time scale
186 BSMotor.Infinite, // decay time scale
187 BSMotor.InfiniteVector, // friction timescale
188 1f // efficiency
189 );
190 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
191
192 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
193 {
194 // TODO: Decide if the step parameters should be changed depending on the avatar's
195 // state (flying, colliding, ...). There is code in ODE to do this.
196
197 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
198 // specified for the avatar is the one that should be used. For falling, if the avatar
199 // is not flying and is not colliding then it is presumed to be falling and the Z
200 // component is not fooled with (thus allowing gravity to do its thing).
201 // When the avatar is standing, though, the user has specified a velocity of zero and
202 // the avatar should be standing. But if the avatar is pushed by something in the world
203 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
204 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
205 // errors can creap in and the avatar will slowly float off in some direction.
206 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
207 // from real pushing.
208 // The code below uses whether the collider is static or moving to decide whether to zero motion.
209
210 _velocityMotor.Step(timeStep);
211
212 // If we're not supposed to be moving, make sure things are zero.
213 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
214 {
215 // The avatar shouldn't be moving
216 _velocityMotor.Zero();
217
218 if (IsColliding)
219 {
220 // If we are colliding with a stationary object, presume we're standing and don't move around
221 if (!ColliderIsMoving)
222 {
223 DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
224 ZeroMotion(true /* inTaintTime */);
225 }
226
227 // Standing has more friction on the ground
228 if (Friction != BSParam.AvatarStandingFriction)
229 {
230 Friction = BSParam.AvatarStandingFriction;
231 PhysicsScene.PE.SetFriction(PhysBody, Friction);
232 }
233 }
234 else
235 {
236 if (Flying)
237 {
238 // Flying and not collising and velocity nearly zero.
239 ZeroMotion(true /* inTaintTime */);
240 }
241 }
242
243 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
244 }
245 else
246 {
247 // Supposed to be moving.
248 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
249
250 if (Friction != BSParam.AvatarFriction)
251 {
252 // Probably starting up walking. Set friction to moving friction.
253 Friction = BSParam.AvatarFriction;
254 PhysicsScene.PE.SetFriction(PhysBody, Friction);
255 }
256
257 // If falling, we keep the world's downward vector no matter what the other axis specify.
258 // The check for _velocity.Z < 0 makes jumping work (temporary upward force).
259 if (!Flying && !IsColliding)
260 {
261 if (_velocity.Z < 0)
262 stepVelocity.Z = _velocity.Z;
263 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
264 }
265
266 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
267 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
268
269 // Should we check for move force being small and forcing velocity to zero?
270
271 // Add special movement force to allow avatars to walk up stepped surfaces.
272 moveForce += WalkUpStairs();
273
274 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
275 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
276 }
277 });
278 }
279
280 // Decide if the character is colliding with a low object and compute a force to pop the
281 // avatar up so it can walk up and over the low objects.
282 private OMV.Vector3 WalkUpStairs()
283 {
284 OMV.Vector3 ret = OMV.Vector3.Zero;
285
286 // This test is done if moving forward, not flying and is colliding with something.
287 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
288 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
289 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
290 {
291 // The range near the character's feet where we will consider stairs
292 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
293 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
294
295 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
296 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
297 {
298 // Don't care about collisions with the terrain
299 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
300 {
301 OMV.Vector3 touchPosition = kvp.Value.Position;
302 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
303 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
304 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
305 {
306 // This contact is within the 'near the feet' range.
307 // The normal should be our contact point to the object so it is pointing away
308 // thus the difference between our facing orientation and the normal should be small.
309 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
310 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
311 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
312 if (diff < BSParam.AvatarStepApproachFactor)
313 {
314 // Found the stairs contact point. Push up a little to raise the character.
315 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
316 ret = new OMV.Vector3(0f, 0f, upForce);
317
318 // Also move the avatar up for the new height
319 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
320 ForcePosition = RawPosition + displacement;
321 }
322 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
323 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
324 }
325 }
326 }
327 }
328
329 return ret;
171 } 330 }
172 331
173 public override void RequestPhysicsterseUpdate() 332 public override void RequestPhysicsterseUpdate()
@@ -185,24 +344,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 344 }
186 345
187 set { 346 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 347 _size = value;
190 ComputeAvatarScale(_size); 348 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
349 // replace with the default values.
350 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
351 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
352
353 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 354 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 355 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 356 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
194 357
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 358 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 359 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 360 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 361 {
362 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
363 UpdatePhysicalMassProperties(RawMass, true);
364 // Make sure this change appears as a property update event
365 PhysicsScene.PE.PushUpdate(PhysBody);
366 }
199 }); 367 });
200 368
201 } 369 }
202 } 370 }
203 371
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 372 public override PrimitiveBaseShape Shape
207 { 373 {
208 set { BaseShape = value; } 374 set { BaseShape = value; }
@@ -219,6 +385,10 @@ public sealed class BSCharacter : BSPhysObject
219 public override bool Selected { 385 public override bool Selected {
220 set { _selected = value; } 386 set { _selected = value; }
221 } 387 }
388 public override bool IsSelected
389 {
390 get { return _selected; }
391 }
222 public override void CrossingFailure() { return; } 392 public override void CrossingFailure() { return; }
223 public override void link(PhysicsActor obj) { return; } 393 public override void link(PhysicsActor obj) { return; }
224 public override void delink() { return; } 394 public override void delink() { return; }
@@ -236,7 +406,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 406 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 407 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 408 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 409 if (PhysBody.HasPhysicalBody)
410 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 411 });
241 } 412 }
242 public override void ZeroAngularMotion(bool inTaintTime) 413 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +416,13 @@ public sealed class BSCharacter : BSPhysObject
245 416
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 418 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 419 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 420 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 421 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 422 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
423 // The next also get rid of applied linear force but the linear velocity is untouched.
424 PhysicsScene.PE.ClearForces(PhysBody);
425 }
252 }); 426 });
253 } 427 }
254 428
@@ -263,29 +437,31 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 437 public override OMV.Vector3 Position {
264 get { 438 get {
265 // Don't refetch the position because this function is called a zillion times 439 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 440 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 441 return _position;
268 } 442 }
269 set { 443 set {
270 _position = value; 444 _position = value;
271 PositionSanityCheck();
272 445
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 446 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 447 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 448 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 449 PositionSanityCheck();
450 ForcePosition = _position;
277 }); 451 });
278 } 452 }
279 } 453 }
280 public override OMV.Vector3 ForcePosition { 454 public override OMV.Vector3 ForcePosition {
281 get { 455 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 456 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 457 return _position;
284 } 458 }
285 set { 459 set {
286 _position = value; 460 _position = value;
287 PositionSanityCheck(); 461 if (PhysBody.HasPhysicalBody)
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 462 {
463 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
464 }
289 } 465 }
290 } 466 }
291 467
@@ -297,17 +473,28 @@ public sealed class BSCharacter : BSPhysObject
297 { 473 {
298 bool ret = false; 474 bool ret = false;
299 475
476 // TODO: check for out of bounds
477 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
478 {
479 // The character is out of the known/simulated area.
480 // Force the avatar position to be within known. ScenePresence will use the position
481 // plus the velocity to decide if the avatar is moving out of the region.
482 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
483 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
484 return true;
485 }
486
300 // If below the ground, move the avatar up 487 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 488 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
302 if (Position.Z < terrainHeight) 489 if (Position.Z < terrainHeight)
303 { 490 {
304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 491 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
305 _position.Z = terrainHeight + 2.0f; 492 _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
306 ret = true; 493 ret = true;
307 } 494 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 495 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 496 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 497 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 498 if (Position.Z < waterHeight)
312 { 499 {
313 _position.Z = waterHeight; 500 _position.Z = waterHeight;
@@ -315,7 +502,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 502 }
316 } 503 }
317 504
318 // TODO: check for out of bounds
319 return ret; 505 return ret;
320 } 506 }
321 507
@@ -332,7 +518,7 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 518 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 519 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 520 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 521 ForcePosition = _position;
336 }); 522 });
337 ret = true; 523 ret = true;
338 } 524 }
@@ -345,10 +531,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 531 public override float RawMass {
346 get {return _mass; } 532 get {return _mass; }
347 } 533 }
348 public override void UpdatePhysicalMassProperties(float physMass) 534 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 535 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 536 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 537 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 538 }
353 539
354 public override OMV.Vector3 Force { 540 public override OMV.Vector3 Force {
@@ -359,7 +545,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 545 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 546 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 547 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 548 if (PhysBody.HasPhysicalBody)
549 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 550 });
364 } 551 }
365 } 552 }
@@ -376,6 +563,37 @@ public sealed class BSCharacter : BSPhysObject
376 563
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 564 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 565 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
566
567 // Sets the target in the motor. This starts the changing of the avatar's velocity.
568 public override OMV.Vector3 TargetVelocity
569 {
570 get
571 {
572 return m_targetVelocity;
573 }
574 set
575 {
576 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
577 m_targetVelocity = value;
578 OMV.Vector3 targetVel = value;
579 if (_setAlwaysRun)
580 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
581
582 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
583 {
584 _velocityMotor.Reset();
585 _velocityMotor.SetTarget(targetVel);
586 _velocityMotor.SetCurrent(_velocity);
587 _velocityMotor.Enabled = true;
588 });
589 }
590 }
591 public override OMV.Vector3 RawVelocity
592 {
593 get { return _velocity; }
594 set { _velocity = value; }
595 }
596 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 597 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 598 get { return _velocity; }
381 set { 599 set {
@@ -383,6 +601,11 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 601 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 602 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 603 {
604 _velocityMotor.Reset();
605 _velocityMotor.SetCurrent(_velocity);
606 _velocityMotor.SetTarget(_velocity);
607 _velocityMotor.Enabled = false;
608
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 609 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 610 ForceVelocity = _velocity;
388 }); 611 });
@@ -391,30 +614,11 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 614 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 615 get { return _velocity; }
393 set { 616 set {
394 // Depending on whether the avatar is moving or not, change the friction 617 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
395 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0)
397 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 }
403 }
404 else
405 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 {
408 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 }
411 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415 618
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 619 _velocity = value;
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 620 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
621 PhysicsScene.PE.Activate(PhysBody, true);
418 } 622 }
419 } 623 }
420 public override OMV.Vector3 Torque { 624 public override OMV.Vector3 Torque {
@@ -439,13 +643,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 643 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 644 get { return _orientation; }
441 set { 645 set {
442 _orientation = value; 646 // 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); 647 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 648 if (_orientation != value)
445 { 649 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 650 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 651 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 652 {
653 ForceOrientation = _orientation;
654 });
655 }
449 } 656 }
450 } 657 }
451 // Go directly to Bullet to get/set the value. 658 // Go directly to Bullet to get/set the value.
@@ -453,13 +660,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 660 {
454 get 661 get
455 { 662 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 663 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 664 return _orientation;
458 } 665 }
459 set 666 set
460 { 667 {
461 _orientation = value; 668 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 669 if (PhysBody.HasPhysicalBody)
670 {
671 // _position = PhysicsScene.PE.GetPosition(BSBody);
672 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
673 }
463 } 674 }
464 } 675 }
465 public override int PhysicsActorType { 676 public override int PhysicsActorType {
@@ -478,10 +689,14 @@ public sealed class BSCharacter : BSPhysObject
478 public override bool IsStatic { 689 public override bool IsStatic {
479 get { return false; } 690 get { return false; }
480 } 691 }
692 public override bool IsPhysicallyActive {
693 get { return true; }
694 }
481 public override bool Flying { 695 public override bool Flying {
482 get { return _flying; } 696 get { return _flying; }
483 set { 697 set {
484 _flying = value; 698 _flying = value;
699
485 // simulate flying by changing the effect of gravity 700 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 701 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 702 }
@@ -500,27 +715,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 715 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 716 set { _throttleUpdates = value; }
502 } 717 }
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 { 718 public override bool FloatOnWater {
516 set { 719 set {
517 _floatOnWater = value; 720 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 721 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 722 {
520 if (_floatOnWater) 723 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 724 {
522 else 725 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 726 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
727 else
728 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
729 }
524 }); 730 });
525 } 731 }
526 } 732 }
@@ -549,11 +755,16 @@ public sealed class BSCharacter : BSPhysObject
549 } 755 }
550 public override float ForceBuoyancy { 756 public override float ForceBuoyancy {
551 get { return _buoyancy; } 757 get { return _buoyancy; }
552 set { _buoyancy = value; 758 set {
759 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
760
761 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 762 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 763 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 764 float grav = BSParam.Gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 765 Gravity = new OMV.Vector3(0f, 0f, grav);
766 if (PhysBody.HasPhysicalBody)
767 PhysicsScene.PE.SetGravity(PhysBody, Gravity);
557 } 768 }
558 } 769 }
559 770
@@ -589,24 +800,33 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 800 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 801 public override float APIDDamping { set { return; } }
591 802
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 803 public override void AddForce(OMV.Vector3 force, bool pushforce)
804 {
805 // Since this force is being applied in only one step, make this a force per second.
806 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
807 AddForce(addForce, pushforce, false);
808 }
809 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 810 if (force.IsFinite())
594 { 811 {
595 _force.X += force.X; 812 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
596 _force.Y += force.Y; 813 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
597 _force.Z += force.Z; 814
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 815 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 816 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 817 // Bullet adds this central force to the total force for this tick
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 818 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
819 if (PhysBody.HasPhysicalBody)
820 {
821 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
822 }
603 }); 823 });
604 } 824 }
605 else 825 else
606 { 826 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 827 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
828 return;
608 } 829 }
609 //m_lastUpdateSent = false;
610 } 830 }
611 831
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 832 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +834,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 834 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 835 }
616 836
617 private void ComputeAvatarScale(OMV.Vector3 size) 837 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 838 {
619 // The 'size' given by the simulator is the mid-point of the avatar 839 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 840
621 841 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 842 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 843 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 844 // shape to be the size desired.
625 845 // 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 846 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 847 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 848 // dimension is the radius of the capsule. Even though some of the code allows
849 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
850
851 // Scale is multiplier of radius with one of "0.5"
852 newScale.X = size.X / 2f;
853 newScale.Y = size.Y / 2f;
629 854
630 // The total scale height is the central cylindar plus the caps on the two ends. 855 // 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); 856 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
857 // If smaller than the endcaps, just fake like we're almost that small
858 if (newScale.Z < 0)
859 newScale.Z = 0.1f;
632 860
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 861 return newScale;
634 Scale = newScale / 2f;
635 } 862 }
636 863
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 864 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,16 +866,16 @@ public sealed class BSCharacter : BSPhysObject
639 { 866 {
640 _avatarVolume = (float)( 867 _avatarVolume = (float)(
641 Math.PI 868 Math.PI
642 * Scale.X 869 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 870 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 871 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 872 + 1.33333333f
646 * Math.PI 873 * Math.PI
647 * Scale.X 874 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 875 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 876 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 877 );
651 _mass = _avatarDensity * _avatarVolume; 878 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
652 } 879 }
653 880
654 // The physics engine says that properties have updated. Update same and inform 881 // The physics engine says that properties have updated. Update same and inform
@@ -657,27 +884,30 @@ public sealed class BSCharacter : BSPhysObject
657 { 884 {
658 _position = entprop.Position; 885 _position = entprop.Position;
659 _orientation = entprop.Rotation; 886 _orientation = entprop.Rotation;
660 _velocity = entprop.Velocity; 887
888 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
889 // and will send agent updates to the clients if velocity changes by more than
890 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
891 // extra updates.
892 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
893 _velocity = entprop.Velocity;
894
661 _acceleration = entprop.Acceleration; 895 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 896 _rotationalVelocity = entprop.RotationalVelocity;
897
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 898 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 899 if (PositionSanityCheck(true))
900 {
901 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
902 entprop.Position = _position;
903 }
665 904
666 // remember the current and last set values 905 // remember the current and last set values
667 LastEntityProperties = CurrentEntityProperties; 906 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 907 CurrentEntityProperties = entprop;
669 908
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 909 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 910 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
681 911
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 912 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 913 // 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..476a0e5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -39,51 +39,50 @@ 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 // 6 Dof constraint based on a midpoint between the two constrained bodies
61 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 : base(world)
64 { 65 {
65 m_world = world;
66 m_body1 = obj1; 66 m_body1 = obj1;
67 m_body2 = obj2; 67 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 72 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}", 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("X"), obj2.ID, obj2.ptr.ToString("X")); 74 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
75 m_enabled = false; 75 m_enabled = false;
76 } 76 }
77 else 77 else
78 { 78 {
79 m_constraint = new BulletConstraint( 79 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, 80 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 81 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 82 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"), 83 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 84 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
86 if (m_constraint.ptr == IntPtr.Zero) 85 if (!m_constraint.HasPhysicalConstraint)
87 { 86 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 87 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 88 LogHeader, obj1.ID, obj2.ID);
@@ -96,12 +95,27 @@ public sealed class BSConstraint6Dof : BSConstraint
96 } 95 }
97 } 96 }
98 97
98 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
99 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
100 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
101 : base(world)
102 {
103 m_body1 = obj1;
104 m_body2 = obj1; // Look out for confusion down the road
105 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
106 frameInBloc, frameInBrot,
107 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
108 m_enabled = true;
109 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
110 BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString);
111 }
112
99 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 113 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
100 { 114 {
101 bool ret = false; 115 bool ret = false;
102 if (m_enabled) 116 if (m_enabled)
103 { 117 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 118 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
105 ret = true; 119 ret = true;
106 } 120 }
107 return ret; 121 return ret;
@@ -112,9 +126,9 @@ public sealed class BSConstraint6Dof : BSConstraint
112 bool ret = false; 126 bool ret = false;
113 if (m_enabled) 127 if (m_enabled)
114 { 128 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 129 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); 130 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); 131 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true; 132 ret = true;
119 } 133 }
120 return ret; 134 return ret;
@@ -125,7 +139,7 @@ public sealed class BSConstraint6Dof : BSConstraint
125 bool ret = false; 139 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 140 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled) 141 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); 142 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
129 return ret; 143 return ret;
130 } 144 }
131 145
@@ -135,7 +149,7 @@ public sealed class BSConstraint6Dof : BSConstraint
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 149 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled) 150 if (m_enabled)
137 { 151 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 152 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", 153 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); 154 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 } 155 }
@@ -146,7 +160,7 @@ public sealed class BSConstraint6Dof : BSConstraint
146 { 160 {
147 bool ret = false; 161 bool ret = false;
148 if (m_enabled) 162 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); 163 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
150 return ret; 164 return ret;
151 } 165 }
152} 166}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index a9fd826..5c8d94e 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>();
@@ -117,8 +117,7 @@ public sealed class BSConstraintCollection : IDisposable
117 if (this.TryGetConstraint(body1, body2, out constrain)) 117 if (this.TryGetConstraint(body1, body2, out constrain))
118 { 118 {
119 // remove the constraint from our collection 119 // remove the constraint from our collection
120 RemoveAndDestroyConstraint(constrain); 120 ret = RemoveAndDestroyConstraint(constrain);
121 ret = true;
122 } 121 }
123 } 122 }
124 123
@@ -126,17 +125,19 @@ public sealed class BSConstraintCollection : IDisposable
126 } 125 }
127 126
128 // The constraint MUST exist in the collection 127 // The constraint MUST exist in the collection
128 // Could be called if the constraint was previously removed.
129 // Return 'true' if the constraint was actually removed and disposed.
129 public bool RemoveAndDestroyConstraint(BSConstraint constrain) 130 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
130 { 131 {
132 bool removed = false;
131 lock (m_constraints) 133 lock (m_constraints)
132 { 134 {
133 // remove the constraint from our collection 135 // remove the constraint from our collection
134 m_constraints.Remove(constrain); 136 removed = m_constraints.Remove(constrain);
135 } 137 }
136 // tell the engine that all its structures need to be freed 138 // Dispose() is safe to call multiple times
137 constrain.Dispose(); 139 constrain.Dispose();
138 // we destroyed something 140 return removed;
139 return true;
140 } 141 }
141 142
142 // Remove all constraints that reference the passed body. 143 // Remove all constraints that reference the passed body.
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..65df741 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -24,28 +24,16 @@
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; 38using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
@@ -80,10 +68,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 68 private Quaternion m_referenceFrame = Quaternion.Identity;
81 69
82 // Linear properties 70 // Linear properties
71 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 72 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 73 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 74 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; 75 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 76 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 77 private float m_linearMotorTimescale = 0;
@@ -93,16 +81,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 81 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 82
95 //Angular properties 83 //Angular properties
84 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 85 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 86 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 87 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 88 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 89 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
101 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 90 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
102 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 91 private Vector3 m_lastAngularVelocity = Vector3.Zero;
103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 92 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
104 93
105 //Deflection properties 94 //Deflection properties
95 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
106 private float m_angularDeflectionEfficiency = 0; 96 private float m_angularDeflectionEfficiency = 0;
107 private float m_angularDeflectionTimescale = 0; 97 private float m_angularDeflectionTimescale = 0;
108 private float m_linearDeflectionEfficiency = 0; 98 private float m_linearDeflectionEfficiency = 0;
@@ -114,33 +104,68 @@ namespace OpenSim.Region.Physics.BulletSPlugin
114 private float m_bankingTimescale = 0; 104 private float m_bankingTimescale = 0;
115 105
116 //Hover and Buoyancy properties 106 //Hover and Buoyancy properties
107 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
117 private float m_VhoverHeight = 0f; 108 private float m_VhoverHeight = 0f;
118 private float m_VhoverEfficiency = 0f; 109 private float m_VhoverEfficiency = 0f;
119 private float m_VhoverTimescale = 0f; 110 private float m_VhoverTimescale = 0f;
120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 111 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. 112 // 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) 113 private float m_VehicleBuoyancy = 0f;
123 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 114 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 115
126 //Attractor properties 116 //Attractor properties
127 private float m_verticalAttractionEfficiency = 1.0f; // damped 117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 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 // For debugging, flags to turn on and off individual corrections.
128 public bool enableAngularVerticalAttraction;
129 public bool enableAngularDeflection;
130 public bool enableAngularBanking;
129 131
130 public BSDynamics(BSScene myScene, BSPrim myPrim) 132 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 { 133 {
132 PhysicsScene = myScene; 134 PhysicsScene = myScene;
133 Prim = myPrim; 135 Prim = myPrim;
134 Type = Vehicle.TYPE_NONE; 136 Type = Vehicle.TYPE_NONE;
137 SetupVehicleDebugging();
138 }
139
140 // Stopgap debugging enablement. Allows source level debugging but still checking
141 // in changes by making enablement of debugging flags from INI file.
142 public void SetupVehicleDebugging()
143 {
144 enableAngularVerticalAttraction = true;
145 enableAngularDeflection = false;
146 enableAngularBanking = true;
147 if (BSParam.VehicleDebuggingEnabled)
148 {
149 enableAngularVerticalAttraction = true;
150 enableAngularDeflection = false;
151 enableAngularBanking = false;
152 }
135 } 153 }
136 154
137 // Return 'true' if this vehicle is doing vehicle things 155 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive 156 public bool IsActive
139 { 157 {
140 get { return Type != Vehicle.TYPE_NONE; } 158 get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); }
141 } 159 }
142 160
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 161 // Return 'true' if this a vehicle that should be sitting on the ground
162 public bool IsGroundVehicle
163 {
164 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
165 }
166
167 #region Vehicle parameter setting
168 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
144 { 169 {
145 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 170 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
146 switch (pParam) 171 switch (pParam)
@@ -152,13 +177,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 177 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 178 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 179 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 180 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
181 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 182 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 183 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 184 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
185 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 186 break;
160 case Vehicle.BANKING_EFFICIENCY: 187 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 188 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 189 break;
163 case Vehicle.BANKING_MIX: 190 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 191 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +194,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 194 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 195 break;
169 case Vehicle.BUOYANCY: 196 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 197 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
198 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
171 break; 199 break;
172 case Vehicle.HOVER_EFFICIENCY: 200 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 201 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 202 break;
175 case Vehicle.HOVER_HEIGHT: 203 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 204 m_VhoverHeight = pValue;
@@ -185,33 +213,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 213 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 214 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 215 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 216 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
217 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 218 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 219 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 220 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
221 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 222 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 223 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 224 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
225 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 226 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 227 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 228 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
229 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 230 break;
199 231
200 // These are vector properties but the engine lets you use a single float value to 232 // 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 233 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 235 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 237 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 239 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 240 m_angularMotor.Zero();
241 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 242 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 243 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 244 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
245 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 246 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 247 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 248 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 249 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
250 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 251 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 252 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 253 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +263,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 263 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 264 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
266 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 267 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 270 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 271 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 272 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 274 m_angularMotor.Zero();
275 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 276 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 278 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
279 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 280 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 281 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 282 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 283 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
284 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 285 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 286 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 287 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -281,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
281 } 321 }
282 } 322 }
283 323
284 internal void ProcessTypeChange(Vehicle pType) 324 public void ProcessTypeChange(Vehicle pType)
285 { 325 {
286 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
287 // Set Defaults For Type 327 // Set Defaults For Type
@@ -303,7 +343,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 343 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 344 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 345 m_VehicleBuoyancy = 0;
306 346
307 m_linearDeflectionEfficiency = 1; 347 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 348 m_linearDeflectionTimescale = 1;
309 349
@@ -319,6 +359,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 359
320 m_referenceFrame = Quaternion.Identity; 360 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 361 m_flags = (VehicleFlag)0;
362
322 break; 363 break;
323 364
324 case Vehicle.TYPE_SLED: 365 case Vehicle.TYPE_SLED:
@@ -351,10 +392,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 392 m_bankingMix = 1;
352 393
353 m_referenceFrame = Quaternion.Identity; 394 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 395 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 396 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 397 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 398 | VehicleFlag.HOVER_UP_ONLY);
399 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
400 | VehicleFlag.LIMIT_ROLL_ONLY
401 | VehicleFlag.LIMIT_MOTOR_UP);
402
358 break; 403 break;
359 case Vehicle.TYPE_CAR: 404 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 405 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +543,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 543 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 544 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 545 m_bankingTimescale = 5;
546
501 m_referenceFrame = Quaternion.Identity; 547 m_referenceFrame = Quaternion.Identity;
502 548
503 m_referenceFrame = Quaternion.Identity; 549 m_referenceFrame = Quaternion.Identity;
@@ -510,152 +556,467 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 556 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 557 break;
512 } 558 }
559
560 // Update any physical parameters based on this type.
561 Refresh();
562
563 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
564 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
565 1f);
566 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
567
568 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
569 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
570 1f);
571 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
572
573 /* Not implemented
574 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
575 BSMotor.Infinite, BSMotor.InfiniteVector,
576 m_verticalAttractionEfficiency);
577 // Z goes away and we keep X and Y
578 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
579 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
580 */
581 }
582 #endregion // Vehicle parameter setting
583
584 public void Refresh()
585 {
586 // If asking for a refresh, reset the physical parameters before the next simulation step.
587 PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate()
588 {
589 SetPhysicalParameters();
590 });
513 } 591 }
514 592
515 // Some of the properties of this prim may have changed. 593 // Some of the properties of this prim may have changed.
516 // Do any updating needed for a vehicle 594 // Do any updating needed for a vehicle
517 public void Refresh() 595 private void SetPhysicalParameters()
518 { 596 {
519 if (IsActive) 597 if (IsActive)
520 { 598 {
521 // Friction effects are handled by this vehicle code 599 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 600 m_vehicleMass = Prim.TotalMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); 601
524 602 // Friction affects are handled by this vehicle code
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 603 PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction);
526 604 PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution);
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 605
606 // Moderate angular movement introduced by Bullet.
607 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
608 // Maybe compute linear and angular factor and damping from params.
609 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping);
610 PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor);
611 PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor);
612
613 // Vehicles report collision events so we know when it's on the ground
614 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
615
616 Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
617 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia);
618 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
619
620 // Set the gravity for the vehicle depending on the buoyancy
621 // TODO: what should be done if prim and vehicle buoyancy differ?
622 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
623 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
624 PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero);
625
626 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
627 Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity,
628 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
629 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
630 );
631 }
632 else
633 {
634 if (Prim.PhysBody.HasPhysicalBody)
635 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 636 }
529 } 637 }
530 638
531 public bool RemoveBodyDependencies(BSPhysObject prim) 639 public bool RemoveBodyDependencies(BSPhysObject prim)
532 { 640 {
533 // If active, we need to add our properties back when the body is rebuilt. 641 Refresh();
534 return IsActive; 642 return IsActive;
535 } 643 }
536 644
537 public void RestoreBodyDependencies(BSPhysObject prim) 645 #region Known vehicle value functions
646 // Vehicle physical parameters that we buffer from constant getting and setting.
647 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
648 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
649 // This does two things: 1) saves continuious calls into unmanaged code, and
650 // 2) signals when a physics property update must happen back to the simulator
651 // to update values modified for the vehicle.
652 private int m_knownChanged;
653 private int m_knownHas;
654 private float m_knownTerrainHeight;
655 private float m_knownWaterLevel;
656 private Vector3 m_knownPosition;
657 private Vector3 m_knownVelocity;
658 private Vector3 m_knownForce;
659 private Vector3 m_knownForceImpulse;
660 private Quaternion m_knownOrientation;
661 private Vector3 m_knownRotationalVelocity;
662 private Vector3 m_knownRotationalForce;
663 private Vector3 m_knownRotationalImpulse;
664 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
665
666 private const int m_knownChangedPosition = 1 << 0;
667 private const int m_knownChangedVelocity = 1 << 1;
668 private const int m_knownChangedForce = 1 << 2;
669 private const int m_knownChangedForceImpulse = 1 << 3;
670 private const int m_knownChangedOrientation = 1 << 4;
671 private const int m_knownChangedRotationalVelocity = 1 << 5;
672 private const int m_knownChangedRotationalForce = 1 << 6;
673 private const int m_knownChangedRotationalImpulse = 1 << 7;
674 private const int m_knownChangedTerrainHeight = 1 << 8;
675 private const int m_knownChangedWaterLevel = 1 << 9;
676 private const int m_knownChangedForwardVelocity = 1 <<10;
677
678 public void ForgetKnownVehicleProperties()
679 {
680 m_knownHas = 0;
681 m_knownChanged = 0;
682 }
683 // Push all the changed values back into the physics engine
684 public void PushKnownChanged()
685 {
686 if (m_knownChanged != 0)
687 {
688 if ((m_knownChanged & m_knownChangedPosition) != 0)
689 Prim.ForcePosition = m_knownPosition;
690
691 if ((m_knownChanged & m_knownChangedOrientation) != 0)
692 Prim.ForceOrientation = m_knownOrientation;
693
694 if ((m_knownChanged & m_knownChangedVelocity) != 0)
695 {
696 Prim.ForceVelocity = m_knownVelocity;
697 // Fake out Bullet by making it think the velocity is the same as last time.
698 // Bullet does a bunch of smoothing for changing parameters.
699 // Since the vehicle is demanding this setting, we override Bullet's smoothing
700 // by telling Bullet the value was the same last time.
701 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
702 }
703
704 if ((m_knownChanged & m_knownChangedForce) != 0)
705 Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
706
707 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
708 Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
709
710 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
711 {
712 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
713 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
714 }
715
716 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
717 Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
718
719 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
720 {
721 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
722 }
723
724 // If we set one of the values (ie, the physics engine didn't do it) we must force
725 // an UpdateProperties event to send the changes up to the simulator.
726 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
727 }
728 m_knownChanged = 0;
729 }
730
731 // Since the computation of terrain height can be a little involved, this routine
732 // is used to fetch the height only once for each vehicle simulation step.
733 Vector3 lastRememberedHeightPos;
734 private float GetTerrainHeight(Vector3 pos)
538 { 735 {
539 if (Prim.LocalID != prim.LocalID) 736 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
540 { 737 {
541 // The call should be on us by our prim. Error if not. 738 lastRememberedHeightPos = pos;
542 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", 739 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
543 LogHeader, prim.LocalID, Prim.LocalID); 740 m_knownHas |= m_knownChangedTerrainHeight;
544 return; 741 }
742 return m_knownTerrainHeight;
743 }
744
745 // Since the computation of water level can be a little involved, this routine
746 // is used ot fetch the level only once for each vehicle simulation step.
747 private float GetWaterLevel(Vector3 pos)
748 {
749 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
750 {
751 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
752 m_knownHas |= m_knownChangedWaterLevel;
753 }
754 return (float)m_knownWaterLevel;
755 }
756
757 private Vector3 VehiclePosition
758 {
759 get
760 {
761 if ((m_knownHas & m_knownChangedPosition) == 0)
762 {
763 m_knownPosition = Prim.ForcePosition;
764 m_knownHas |= m_knownChangedPosition;
765 }
766 return m_knownPosition;
767 }
768 set
769 {
770 m_knownPosition = value;
771 m_knownChanged |= m_knownChangedPosition;
772 m_knownHas |= m_knownChangedPosition;
545 } 773 }
546 Refresh();
547 } 774 }
548 775
776 private Quaternion VehicleOrientation
777 {
778 get
779 {
780 if ((m_knownHas & m_knownChangedOrientation) == 0)
781 {
782 m_knownOrientation = Prim.ForceOrientation;
783 m_knownHas |= m_knownChangedOrientation;
784 }
785 return m_knownOrientation;
786 }
787 set
788 {
789 m_knownOrientation = value;
790 m_knownChanged |= m_knownChangedOrientation;
791 m_knownHas |= m_knownChangedOrientation;
792 }
793 }
794
795 private Vector3 VehicleVelocity
796 {
797 get
798 {
799 if ((m_knownHas & m_knownChangedVelocity) == 0)
800 {
801 m_knownVelocity = Prim.ForceVelocity;
802 m_knownHas |= m_knownChangedVelocity;
803 }
804 return m_knownVelocity;
805 }
806 set
807 {
808 m_knownVelocity = value;
809 m_knownChanged |= m_knownChangedVelocity;
810 m_knownHas |= m_knownChangedVelocity;
811 }
812 }
813
814 private void VehicleAddForce(Vector3 pForce)
815 {
816 if ((m_knownHas & m_knownChangedForce) == 0)
817 {
818 m_knownForce = Vector3.Zero;
819 m_knownHas |= m_knownChangedForce;
820 }
821 m_knownForce += pForce;
822 m_knownChanged |= m_knownChangedForce;
823 }
824
825 private void VehicleAddForceImpulse(Vector3 pImpulse)
826 {
827 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
828 {
829 m_knownForceImpulse = Vector3.Zero;
830 m_knownHas |= m_knownChangedForceImpulse;
831 }
832 m_knownForceImpulse += pImpulse;
833 m_knownChanged |= m_knownChangedForceImpulse;
834 }
835
836 private Vector3 VehicleRotationalVelocity
837 {
838 get
839 {
840 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
841 {
842 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
843 m_knownHas |= m_knownChangedRotationalVelocity;
844 }
845 return (Vector3)m_knownRotationalVelocity;
846 }
847 set
848 {
849 m_knownRotationalVelocity = value;
850 m_knownChanged |= m_knownChangedRotationalVelocity;
851 m_knownHas |= m_knownChangedRotationalVelocity;
852 }
853 }
854 private void VehicleAddAngularForce(Vector3 aForce)
855 {
856 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
857 {
858 m_knownRotationalForce = Vector3.Zero;
859 }
860 m_knownRotationalForce += aForce;
861 m_knownChanged |= m_knownChangedRotationalForce;
862 m_knownHas |= m_knownChangedRotationalForce;
863 }
864 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
865 {
866 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
867 {
868 m_knownRotationalImpulse = Vector3.Zero;
869 m_knownHas |= m_knownChangedRotationalImpulse;
870 }
871 m_knownRotationalImpulse += pImpulse;
872 m_knownChanged |= m_knownChangedRotationalImpulse;
873 }
874
875 // Vehicle relative forward velocity
876 private Vector3 VehicleForwardVelocity
877 {
878 get
879 {
880 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
881 {
882 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
883 m_knownHas |= m_knownChangedForwardVelocity;
884 }
885 return m_knownForwardVelocity;
886 }
887 }
888 private float VehicleForwardSpeed
889 {
890 get
891 {
892 return VehicleForwardVelocity.X;
893 }
894 }
895
896 #endregion // Known vehicle value functions
897
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 898 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 899 internal void Step(float pTimestep)
551 { 900 {
552 if (!IsActive) return; 901 if (!IsActive) return;
553 902
554 // DEBUG 903 ForgetKnownVehicleProperties();
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564 904
565 MoveLinear(pTimestep); 905 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 906 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 907
571 LimitRotation(pTimestep); 908 LimitRotation(pTimestep);
572 909
573 // remember the position so next step we can limit absolute movement effects 910 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 911 m_lastPositionVector = VehiclePosition;
575 912
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 913 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 914 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 915 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), 916
580 Prim.Inertia, 917 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
581 m_vehicleMass 918 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
582 ); 919
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 920 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 921 Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
585 }// end Step 922 }
586 923
587 // Apply the effect of the linear motor. 924 // Called after the simulation step
588 // Also does hover and float. 925 internal void PostStep(float pTimestep)
926 {
927 if (!IsActive) return;
928
929 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
930 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
931 }
932
933 // Apply the effect of the linear motor and other linear motions (like hover and float).
589 private void MoveLinear(float pTimestep) 934 private void MoveLinear(float pTimestep)
590 { 935 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 936 ComputeLinearVelocity(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
594 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
599 937
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 938 ComputeLinearTerrainHeightCorrection(pTimestep);
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
602 m_lastLinearVelocityVector += addAmount;
603 939
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 940 ComputeLinearHover(pTimestep);
605 m_linearMotorDirection *= (1f - decayFactor);
606 941
607 // Rotate new object velocity from vehicle relative to world coordinates 942 ComputeLinearBlockingEndPoint(pTimestep);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 943
610 // Apply friction for next time 944 ComputeLinearMotorUp(pTimestep);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 945
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 946 ApplyGravity(pTimestep);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 947
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 948 // If not changing some axis, reduce out velocity
617 } 949 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
618 else
619 { 950 {
620 // if what remains of direction is very small, zero it. 951 Vector3 vel = VehicleVelocity;
621 m_linearMotorDirection = Vector3.Zero; 952 if ((m_flags & (VehicleFlag.NO_X)) != 0)
622 m_lastLinearVelocityVector = Vector3.Zero; 953 vel.X = 0;
623 m_newVelocity = Vector3.Zero; 954 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
955 vel.Y = 0;
956 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
957 vel.Z = 0;
958 VehicleVelocity = vel;
959 }
624 960
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 961 // ==================================================================
962 // Clamp high or low velocities
963 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
964 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
965 {
966 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
967 VehicleVelocity /= VehicleVelocity.Length();
968 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
969 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
970 Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
626 } 971 }
972 else if (newVelocityLengthSq < 0.001f)
973 VehicleVelocity = Vector3.Zero;
627 974
628 // m_newVelocity is velocity computed from linear motor in world coordinates 975 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity );
629 976
630 // Gravity and Buoyancy 977 } // end MoveLinear()
631 // There is some gravity, make a gravity force vector that is applied after object velocity.
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
634 978
635 /* 979 public void ComputeLinearVelocity(float pTimestep)
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 980 {
637 // Preserve the current Z velocity 981 // Step the motor from the current value. Get the correction needed this step.
638 Vector3 vel_now = m_prim.Velocity; 982 Vector3 origVelW = VehicleVelocity; // DEBUG
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 983 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
640 */ 984 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
985
986 // Motor is vehicle coordinates. Rotate it to world coordinates
987 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
988
989 // If we're a ground vehicle, don't add any upward Z movement
990 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
991 {
992 if (linearMotorVelocityW.Z > 0f)
993 linearMotorVelocityW.Z = 0f;
994 }
995
996 // Add this correction to the velocity to make it faster/slower.
997 VehicleVelocity += linearMotorVelocityW;
641 998
642 Vector3 pos = Prim.ForcePosition; 999 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={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); 1000 Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity);
1001 }
644 1002
1003 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
1004 {
645 // If below the terrain, move us above the ground a little. 1005 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 1006 // 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. 1007 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 { 1008 {
653 pos.Z = terrainHeight + 2; 1009 // Force position because applying force won't get the vehicle through the terrain
654 Prim.ForcePosition = pos; 1010 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 1011 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1012 VehiclePosition = newPosition;
1013 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1014 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 1015 }
1016 }
657 1017
658 // Check if hovering 1018 public void ComputeLinearHover(float pTimestep)
1019 {
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1020 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 1021 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1022 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +1024,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 1024 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1025 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 1026 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 1027 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 1028 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 1029 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 1030 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 1031 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 1032 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 1033 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 1034 {
@@ -677,45 +1038,63 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1038 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 1039 {
679 // If body is already heigher, use its height as target height 1040 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 1041 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 1042 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 1043 }
1044
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1045 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 1046 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 1047 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 1048 {
1049 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 1050 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 1051 VehiclePosition = pos;
1052
1053 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos);
689 } 1054 }
690 } 1055 }
691 else 1056 else
692 { 1057 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 1058 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 1059 Vector3 hpos = VehiclePosition;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 1060 float verticalError = m_VhoverTargetHeight - hpos.Z;
696 // Replace Vertical speed with correction figure if significant 1061 float verticalCorrection = verticalError / m_VhoverTimescale;
697 if (Math.Abs(verticalError) > 0.01f) 1062 verticalCorrection *= m_VhoverEfficiency;
698 { 1063
699 m_newVelocity.Z += verticalCorrectionVelocity; 1064 hpos.Z += verticalCorrection;
700 //KF: m_VhoverEfficiency is not yet implemented 1065 VehiclePosition = hpos;
701 } 1066
702 else if (verticalError < -0.01) 1067 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
703 { 1068 Vector3 vel = VehicleVelocity;
704 m_newVelocity.Z -= verticalCorrectionVelocity; 1069 vel.Z = 0f;
705 } 1070 VehicleVelocity = vel;
706 else 1071
707 { 1072 /*
708 m_newVelocity.Z = 0f; 1073 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
709 } 1074 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1075 verticalCorrection *= m_vehicleMass;
1076
1077 // TODO: implement m_VhoverEfficiency correctly
1078 VehicleAddForceImpulse(verticalCorrection);
1079 */
1080
1081 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1082 Prim.LocalID, VehiclePosition, m_VhoverEfficiency,
1083 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1084 verticalError, verticalCorrection);
710 } 1085 }
711 1086
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
713 } 1087 }
1088 }
714 1089
1090 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1091 {
1092 bool changed = false;
1093
1094 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 1095 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 1096 if (m_BlockingEndPoint != Vector3.Zero)
717 { 1097 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 1098 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 1099 {
721 pos.X -= posChange.X + 1; 1100 pos.X -= posChange.X + 1;
@@ -743,233 +1122,119 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 1122 }
744 if (changed) 1123 if (changed)
745 { 1124 {
746 Prim.ForcePosition = pos; 1125 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1126 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1127 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 1128 }
750 } 1129 }
1130 return changed;
1131 }
751 1132
752 #region downForce 1133 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 1134 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
754 1135 // used with conjunction with banking: the strength of the banking will decay when the
1136 // vehicle no longer experiences collisions. The decay timescale is the same as
1137 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1138 // when they are in mid jump.
1139 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1140 // This is just using the ground and a general collision check. Should really be using
1141 // a downward raycast to find what is below.
1142 public void ComputeLinearMotorUp(float pTimestep)
1143 {
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1144 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1145 {
757 // If the vehicle is motoring into the sky, get it going back down. 1146 // 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?? 1147 /*
759 float distanceAboveGround = pos.Z - terrainHeight; 1148 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
760 if (distanceAboveGround > 2f) 1149 distanceAboveGround = VehiclePosition.Z - targetHeight;
1150 // Not colliding if the vehicle is off the ground
1151 if (!Prim.IsColliding)
761 { 1152 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1153 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1154 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
765 } 1155 }
766 // TODO: this calculation is all wrong. From the description at 1156 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1157 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1158 // has a decay factor. This says this force should
769 // be computed with a motor. 1159 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1160 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce); 1161 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
772 } 1162 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
773 #endregion // downForce 1163 */
774 1164
775 // If not changing some axis, reduce out velocity 1165 // Another approach is to measure if we're going up. If going up and not colliding,
776 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1166 // the vehicle is in the air. Fix that by pushing down.
777 m_newVelocity.X = 0; 1167 if (!Prim.IsColliding && VehicleVelocity.Z > 0.1)
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1168 {
779 m_newVelocity.Y = 0; 1169 // Get rid of any of the velocity vector that is pushing us up.
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1170 float upVelocity = VehicleVelocity.Z;
781 m_newVelocity.Z = 0; 1171 VehicleVelocity += new Vector3(0, 0, -upVelocity);
782 1172
783 // Clamp REALLY high or low velocities 1173 /*
784 if (m_newVelocity.LengthSquared() > 1e6f) 1174 // If we're pointed up into the air, we should nose down
785 { 1175 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
786 m_newVelocity /= m_newVelocity.Length(); 1176 // The rotation around the Y axis is pitch up or down
787 m_newVelocity *= 1000f; 1177 if (pointingDirection.Y > 0.01f)
1178 {
1179 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1180 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1181 // Rotate into world coordinates and apply to vehicle
1182 angularCorrectionVector *= VehicleOrientation;
1183 VehicleAddAngularForce(angularCorrectionVector);
1184 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1185 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1186 }
1187 */
1188 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1189 Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity);
1190 }
788 } 1191 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f) 1192 }
790 m_newVelocity = Vector3.Zero;
791 1193
792 // Stuff new linear velocity into the vehicle 1194 private void ApplyGravity(float pTimeStep)
793 Prim.ForceVelocity = m_newVelocity; 1195 {
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG 1196 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
795 1197
796 Vector3 totalDownForce = downForce + grav; 1198 // Hack to reduce downward force if the vehicle is probably sitting on the ground
797 if (totalDownForce != Vector3.Zero) 1199 if (Prim.IsColliding && IsGroundVehicle)
798 { 1200 appliedGravity *= BSParam.VehicleGroundGravityFudge;
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
802 1201
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1202 VehicleAddForce(appliedGravity);
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
805 1203
806 } // end MoveLinear() 1204 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1205 Prim.LocalID, m_VehicleGravity,
1206 Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1207 }
807 1208
808 // ======================================================================= 1209 // =======================================================================
1210 // =======================================================================
809 // Apply the effect of the angular motor. 1211 // Apply the effect of the angular motor.
1212 // The 'contribution' is how much angular correction velocity each function wants.
1213 // All the contributions are added together and the resulting velocity is
1214 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1215 private void MoveAngular(float pTimestep)
811 { 1216 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1217 ComputeAngularTurning(pTimestep);
813 // m_angularMotorApply // application frame counter
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
815 // m_angularMotorTimescale // motor angular velocity ramp up rate
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate
817 // m_angularFrictionTimescale // body angular velocity decay rate
818 // m_lastAngularVelocity // what was last applied to body
819
820 if (m_angularMotorDirection.LengthSquared() > 0.0001)
821 {
822 Vector3 origVel = m_angularMotorVelocity;
823 Vector3 origDir = m_angularMotorDirection;
824
825 // new velocity += error / ( time to get there / step interval)
826 // requested direction - current vehicle direction
827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
828 // decay requested direction
829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
830 1218
831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", 1219 ComputeAngularVerticalAttraction();
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
833 }
834 else
835 {
836 m_angularMotorVelocity = Vector3.Zero;
837 }
838 1220
839 #region Vertical attactor 1221 ComputeAngularDeflection();
840 1222
841 Vector3 vertattr = Vector3.Zero; 1223 ComputeAngularBanking();
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844 1224
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 1225 // ==================================================================
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 1226 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
847 { 1227 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 1228 // The vehicle is not adding anything angular wise.
849 if (Prim.IsColliding) 1229 VehicleRotationalVelocity = Vector3.Zero;
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); 1230 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
851
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
853
854 // Create a vector of the vehicle "up" in world coordinates
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
861
862 // Error is 0 (no error) to +/- 2 (max error)
863 if (verticalError.Z < 0.0f)
864 {
865 verticalError.X = 2.0f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y;
867 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
873 // Z is not changed.
874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877
878 // scaling appears better usingsquare-law
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
881 vertattr.X += bounce * angularVelocity.X;
882 vertattr.Y += bounce * angularVelocity.Y;
883
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
890 #region Deflection
891
892 if (m_angularDeflectionEfficiency != 0)
893 {
894 // Compute a scaled vector that points in the preferred axis (X direction)
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 } 1231 }
909 1232 else
910 #endregion
911
912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 { 1233 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1234 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity);
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns
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 } 1235 }
963 1236
964 #endregion 1237 // ==================================================================
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 1238 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1239 if (m_linearMotorOffset != Vector3.Zero)
975 { 1240 {
@@ -985,8 +1250,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1250 //
986 // The torque created is the linear velocity crossed with the offset 1251 // The torque created is the linear velocity crossed with the offset
987 1252
988 // NOTE: this computation does should be in the linear section 1253 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1254 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1255 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1256 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1257 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1260,258 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1260 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1261 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1262 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1263
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1264 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1265 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1266 }
1002 1267
1003 #endregion 1268 }
1269
1270 private void ComputeAngularTurning(float pTimestep)
1271 {
1272 // The user wants this many radians per second angular change?
1273 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1274 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1275
1276 // ==================================================================
1277 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1278 // This flag prevents linear deflection parallel to world z-axis. This is useful
1279 // for preventing ground vehicles with large linear deflection, like bumper cars,
1280 // from climbing their linear deflection into the sky.
1281 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1282 // TODO: This is here because this is where ODE put it but documentation says it
1283 // is a linear effect. Where should this check go?
1284 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1285 // {
1286 // angularMotorContributionV.X = 0f;
1287 // angularMotorContributionV.Y = 0f;
1288 // }
1289
1290 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1291 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
1292 }
1293
1294 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1295 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1296 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1297 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1298 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1299 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1300 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1302 public void ComputeAngularVerticalAttraction()
1303 {
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 // Possible solution derived from a discussion at:
1008 m_lastAngularVelocity.Y = 0; 1309 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1310
1311 // Create a rotation that is only the vehicle's rotation around Z
1312 Vector3 currentEuler = Vector3.Zero;
1313 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1314 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1315
1316 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1317 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1318 // Compute the angle between those to vectors.
1319 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1320 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1321
1322 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1323 // TODO: add 'efficiency'.
1324 differenceAngle /= m_verticalAttractionTimescale;
1325
1326 // Create the quaterian representing the correction angle
1327 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1328
1329 // Turn that quaternion into Euler values to make it into velocities to apply.
1330 Vector3 vertContributionV = Vector3.Zero;
1331 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1332 vertContributionV *= -1f;
1333
1334 VehicleRotationalVelocity += vertContributionV;
1335
1336 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1337 Prim.LocalID,
1338 differenceAxis,
1339 differenceAngle,
1340 correctionRotation,
1341 vertContributionV);
1342
1343 // ===================================================================
1344 /*
1345 Vector3 vertContributionV = Vector3.Zero;
1346 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1347
1348 // Take a vector pointing up and convert it from world to vehicle relative coords.
1349 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1350
1351 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1352 // is now:
1353 // leaning to one side: rotated around the X axis with the Y value going
1354 // from zero (nearly straight up) to one (completely to the side)) or
1355 // leaning front-to-back: rotated around the Y axis with the value of X being between
1356 // zero and one.
1357 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1358
1359 // Y error means needed rotation around X axis and visa versa.
1360 // Since the error goes from zero to one, the asin is the corresponding angle.
1361 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1362 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1363 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1364
1365 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1366 if (verticalError.Z < 0f)
1367 {
1368 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1369 // vertContribution.Y -= PIOverFour;
1370 }
1371
1372 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1373 // Correction happens over a number of seconds.
1374 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1375
1376 // The correction happens over the user's time period
1377 vertContributionV /= m_verticalAttractionTimescale;
1378
1379 // Rotate the vehicle rotation to the world coordinates.
1380 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1381
1382 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1383 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1384 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1385 */
1010 } 1386 }
1387 }
1388
1389 // Angular correction to correct the direction the vehicle is pointing to be
1390 // the direction is should want to be pointing.
1391 // The vehicle is moving in some direction and correct its orientation to it is pointing
1392 // in that direction.
1393 // TODO: implement reference frame.
1394 public void ComputeAngularDeflection()
1395 {
1396 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1397 // approximately the same X or Y correction. When added together (when contributions are combined)
1398 // this creates an over-correction and then wabbling as the target is overshot.
1399 // TODO: rethink how the different correction computations inter-relate.
1011 1400
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1401 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1013 { 1402 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1403 Vector3 deflectContributionV = Vector3.Zero;
1015 Prim.ZeroAngularMotion(true); 1404
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1405 // The direction the vehicle is moving
1406 Vector3 movingDirection = VehicleVelocity;
1407 movingDirection.Normalize();
1408
1409 // If the vehicle is going backward, it is still pointing forward
1410 movingDirection *= Math.Sign(VehicleForwardSpeed);
1411
1412 // The direction the vehicle is pointing
1413 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1414 pointingDirection.Normalize();
1415
1416 // The difference between what is and what should be.
1417 Vector3 deflectionError = movingDirection - pointingDirection;
1418
1419 // Don't try to correct very large errors (not our job)
1420 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1421 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1422 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1423 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1424 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1425 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1426
1427 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1428
1429 // Scale the correction by recovery timescale and efficiency
1430 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency;
1431 deflectContributionV /= m_angularDeflectionTimescale;
1432
1433 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1434
1435 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1436 Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1437 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1438 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1017 } 1439 }
1018 else 1440 }
1441
1442 // Angular change to rotate the vehicle around the Z axis when the vehicle
1443 // is tipped around the X axis.
1444 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1445 // The vertical attractor feature must be enabled in order for the banking behavior to
1446 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1447 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1448 // of the yaw effect will be proportional to the
1449 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1450 // velocity along its preferred axis of motion.
1451 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1452 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1453 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1454 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1455 // Negating the banking coefficient will make it so that the vehicle leans to the
1456 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1457 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1458 // banking vehicles do what you want rather than what the laws of physics allow.
1459 // For example, consider a real motorcycle...it must be moving forward in order for
1460 // it to turn while banking, however video-game motorcycles are often configured
1461 // to turn in place when at a dead stop--because they are often easier to control
1462 // that way using the limited interface of the keyboard or game controller. The
1463 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1464 // banking by functioning as a slider between a banking that is correspondingly
1465 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1466 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1467 // to "dynamic" where the banking is also proportional to its velocity along its
1468 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1469 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1470 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1471 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1472 // make a sluggish vehicle by giving it a timescale of several seconds.
1473 public void ComputeAngularBanking()
1474 {
1475 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1476 {
1020 // Apply to the body. 1477 Vector3 bankingContributionV = Vector3.Zero;
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1478
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1479 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1023 // velocity needs to be scaled by the timestep. 1480 // As the vehicle rolls to the right or left, the Y value will increase from
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1481 // zero (straight up) to 1 or -1 (full tilt right or left)
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1482 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1026 1483
1027 // Decay the angular movement for next time 1484 // Figure out the yaw value for this much roll.
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1485 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1486 // actual error = static turn error + dynamic turn error
1030 1487 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1488
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1489 // TODO: the banking effect should not go to infinity but what to limit it to?
1490 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1491 mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
1492
1493 // Build the force vector to change rotation from what it is to what it should be
1494 bankingContributionV.Z = -mixedYawAngle;
1495
1496 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1497 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1498
1499 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1500 VehicleRotationalVelocity += bankingContributionV;
1501
1502
1503 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1504 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1033 } 1505 }
1034 } //end MoveAngular 1506 }
1035 1507
1508 // This is from previous instantiations of XXXDynamics.cs.
1509 // Applies roll reference frame.
1510 // TODO: is this the right way to separate the code to do this operation?
1511 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1512 internal void LimitRotation(float timestep)
1037 { 1513 {
1038 Quaternion rotq = Prim.ForceOrientation; 1514 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1515 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1516 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1517 {
@@ -1063,12 +1539,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1539 }
1064 if (rotq != m_rot) 1540 if (rotq != m_rot)
1065 { 1541 {
1066 Prim.ForceOrientation = m_rot; 1542 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1543 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1544 }
1069 1545
1070 } 1546 }
1071 1547
1548 private float ClampInRange(float low, float val, float high)
1549 {
1550 return Math.Max(low, Math.Min(val, high));
1551 // return Utils.Clamp(val, low, high);
1552 }
1553
1072 // Invoke the detailed logger and output something if it's enabled. 1554 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1555 private void VDetailLog(string msg, params Object[] args)
1074 { 1556 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..4ece1eb 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]";
@@ -43,11 +52,11 @@ public abstract class BSLinkset
43 Manual = 2 // linkset tied together manually (code moves all the pieces) 52 Manual = 2 // linkset tied together manually (code moves all the pieces)
44 } 53 }
45 // Create the correct type of linkset for this child 54 // Create the correct type of linkset for this child
46 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) 55 public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
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);
@@ -62,10 +71,14 @@ public abstract class BSLinkset
62 ret = new BSLinksetCompound(physScene, parent); 71 ret = new BSLinksetCompound(physScene, parent);
63 break; 72 break;
64 } 73 }
74 if (ret == null)
75 {
76 physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
77 }
65 return ret; 78 return ret;
66 } 79 }
67 80
68 public BSPhysObject LinksetRoot { get; protected set; } 81 public BSPrimLinkable LinksetRoot { get; protected set; }
69 82
70 public BSScene PhysicsScene { get; private set; } 83 public BSScene PhysicsScene { get; private set; }
71 84
@@ -73,7 +86,7 @@ public abstract class BSLinkset
73 public int LinksetID { get; private set; } 86 public int LinksetID { get; private set; }
74 87
75 // The children under the root in this linkset. 88 // The children under the root in this linkset.
76 protected HashSet<BSPhysObject> m_children; 89 protected HashSet<BSPrimLinkable> m_children;
77 90
78 // We lock the diddling of linkset classes to prevent any badness. 91 // We lock the diddling of linkset classes to prevent any badness.
79 // This locks the modification of the instances of this class. Changes 92 // This locks the modification of the instances of this class. Changes
@@ -82,27 +95,13 @@ public abstract class BSLinkset
82 95
83 // Some linksets have a preferred physical shape. 96 // Some linksets have a preferred physical shape.
84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. 97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
85 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
86 { 99 {
87 return BSPhysicsShapeType.SHAPE_UNKNOWN; 100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 101 }
89 102
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 103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
98 protected float m_mass; 104 public float LinksetMass { get; protected set; }
99 public float LinksetMass
100 {
101 get
102 {
103 return m_mass;
104 }
105 }
106 105
107 public virtual bool LinksetIsColliding { get { return false; } } 106 public virtual bool LinksetIsColliding { get { return false; } }
108 107
@@ -116,7 +115,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 115 get { return ComputeLinksetGeometricCenter(); }
117 } 116 }
118 117
119 protected void Initialize(BSScene scene, BSPhysObject parent) 118 protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120 { 119 {
121 // A simple linkset of one (no children) 120 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 121 LinksetID = m_nextLinksetID++;
@@ -125,22 +124,25 @@ public abstract class BSLinkset
125 m_nextLinksetID = 1; 124 m_nextLinksetID = 1;
126 PhysicsScene = scene; 125 PhysicsScene = scene;
127 LinksetRoot = parent; 126 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 127 m_children = new HashSet<BSPrimLinkable>();
129 m_mass = parent.RawMass; 128 LinksetMass = parent.RawMass;
129 Rebuilding = false;
130
131 parent.ClearDisplacement();
130 } 132 }
131 133
132 // Link to a linkset where the child knows the parent. 134 // Link to a linkset where the child knows the parent.
133 // Parent changing should not happen so do some sanity checking. 135 // Parent changing should not happen so do some sanity checking.
134 // We return the parent's linkset so the child can track its membership. 136 // We return the parent's linkset so the child can track its membership.
135 // Called at runtime. 137 // Called at runtime.
136 public BSLinkset AddMeToLinkset(BSPhysObject child) 138 public BSLinkset AddMeToLinkset(BSPrimLinkable child)
137 { 139 {
138 lock (m_linksetActivityLock) 140 lock (m_linksetActivityLock)
139 { 141 {
140 // Don't add the root to its own linkset 142 // Don't add the root to its own linkset
141 if (!IsRoot(child)) 143 if (!IsRoot(child))
142 AddChildToLinkset(child); 144 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass(); 145 LinksetMass = ComputeLinksetMass();
144 } 146 }
145 return this; 147 return this;
146 } 148 }
@@ -149,7 +151,7 @@ public abstract class BSLinkset
149 // Returns a new linkset for the child which is a linkset of one (just the 151 // Returns a new linkset for the child which is a linkset of one (just the
150 // orphened child). 152 // orphened child).
151 // Called at runtime. 153 // Called at runtime.
152 public BSLinkset RemoveMeFromLinkset(BSPhysObject child) 154 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
153 { 155 {
154 lock (m_linksetActivityLock) 156 lock (m_linksetActivityLock)
155 { 157 {
@@ -159,7 +161,7 @@ public abstract class BSLinkset
159 return this; 161 return this;
160 } 162 }
161 RemoveChildFromLinkset(child); 163 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass(); 164 LinksetMass = ComputeLinksetMass();
163 } 165 }
164 166
165 // The child is down to a linkset of just itself 167 // The child is down to a linkset of just itself
@@ -167,7 +169,7 @@ public abstract class BSLinkset
167 } 169 }
168 170
169 // Return 'true' if the passed object is the root object of this linkset 171 // Return 'true' if the passed object is the root object of this linkset
170 public bool IsRoot(BSPhysObject requestor) 172 public bool IsRoot(BSPrimLinkable requestor)
171 { 173 {
172 return (requestor.LocalID == LinksetRoot.LocalID); 174 return (requestor.LocalID == LinksetRoot.LocalID);
173 } 175 }
@@ -178,14 +180,14 @@ public abstract class BSLinkset
178 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 180 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
179 181
180 // Return 'true' if this child is in this linkset 182 // Return 'true' if this child is in this linkset
181 public bool HasChild(BSPhysObject child) 183 public bool HasChild(BSPrimLinkable child)
182 { 184 {
183 bool ret = false; 185 bool ret = false;
184 lock (m_linksetActivityLock) 186 lock (m_linksetActivityLock)
185 { 187 {
186 ret = m_children.Contains(child); 188 ret = m_children.Contains(child);
187 /* Safer version but the above should work 189 /* Safer version but the above should work
188 foreach (BSPhysObject bp in m_children) 190 foreach (BSPrimLinkable bp in m_children)
189 { 191 {
190 if (child.LocalID == bp.LocalID) 192 if (child.LocalID == bp.LocalID)
191 { 193 {
@@ -200,14 +202,14 @@ public abstract class BSLinkset
200 202
201 // Perform an action on each member of the linkset including root prim. 203 // Perform an action on each member of the linkset including root prim.
202 // Depends on the action on whether this should be done at taint time. 204 // Depends on the action on whether this should be done at taint time.
203 public delegate bool ForEachMemberAction(BSPhysObject obj); 205 public delegate bool ForEachMemberAction(BSPrimLinkable obj);
204 public virtual bool ForEachMember(ForEachMemberAction action) 206 public virtual bool ForEachMember(ForEachMemberAction action)
205 { 207 {
206 bool ret = false; 208 bool ret = false;
207 lock (m_linksetActivityLock) 209 lock (m_linksetActivityLock)
208 { 210 {
209 action(LinksetRoot); 211 action(LinksetRoot);
210 foreach (BSPhysObject po in m_children) 212 foreach (BSPrimLinkable po in m_children)
211 { 213 {
212 if (action(po)) 214 if (action(po))
213 break; 215 break;
@@ -218,16 +220,23 @@ public abstract class BSLinkset
218 220
219 // I am the root of a linkset and a new child is being added 221 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 222 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 223 protected abstract void AddChildToLinkset(BSPrimLinkable child);
222 224
223 // I am the root of a linkset and one of my children is being removed. 225 // 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. 226 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 227 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
226 228
227 // When physical properties are changed the linkset needs to recalculate 229 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 230 // its internal properties.
229 // May be called at runtime or taint-time. 231 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 232 public virtual void Refresh(BSPrimLinkable requestor)
233 {
234 LinksetMass = ComputeLinksetMass();
235 }
236
237 // Flag denoting the linkset is in the process of being rebuilt.
238 // Used to know not the schedule a rebuild in the middle of a rebuild.
239 protected bool Rebuilding { get; set; }
231 240
232 // The object is going dynamic (physical). Do any setup necessary 241 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 242 // for a dynamic linkset.
@@ -235,30 +244,26 @@ public abstract class BSLinkset
235 // has not yet been fully constructed. 244 // has not yet been fully constructed.
236 // Return 'true' if any properties updated on the passed object. 245 // Return 'true' if any properties updated on the passed object.
237 // Called at taint-time! 246 // Called at taint-time!
238 public abstract bool MakeDynamic(BSPhysObject child); 247 public abstract bool MakeDynamic(BSPrimLinkable child);
239 248
240 // The object is going static (non-physical). Do any setup necessary 249 // The object is going static (non-physical). Do any setup necessary
241 // for a static linkset. 250 // for a static linkset.
242 // Return 'true' if any properties updated on the passed object. 251 // Return 'true' if any properties updated on the passed object.
243 // Called at taint-time! 252 // Called at taint-time!
244 public abstract bool MakeStatic(BSPhysObject child); 253 public abstract bool MakeStatic(BSPrimLinkable child);
245 254
246 // Called when a parameter update comes from the physics engine for any object 255 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 256 // of the linkset is received.
257 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 258 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 259 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
250 260
251 // Routine used when rebuilding the body of the root of the linkset 261 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 262 // Destroy all the constraints have have been made to root.
253 // This is called when the root body is changing. 263 // This is called when the root body is changing.
254 // Returns 'true' of something was actually removed and would need restoring 264 // Returns 'true' of something was actually removed and would need restoring
255 // Called at taint-time!! 265 // Called at taint-time!!
256 public abstract bool RemoveBodyDependencies(BSPrim child); 266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child);
257
258 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
259 // this routine will restore the removed constraints.
260 // Called at taint-time!!
261 public abstract void RestoreBodyDependencies(BSPrim child);
262 267
263 // ================================================================ 268 // ================================================================
264 protected virtual float ComputeLinksetMass() 269 protected virtual float ComputeLinksetMass()
@@ -268,7 +273,7 @@ public abstract class BSLinkset
268 { 273 {
269 lock (m_linksetActivityLock) 274 lock (m_linksetActivityLock)
270 { 275 {
271 foreach (BSPhysObject bp in m_children) 276 foreach (BSPrimLinkable bp in m_children)
272 { 277 {
273 mass += bp.RawMass; 278 mass += bp.RawMass;
274 } 279 }
@@ -277,6 +282,7 @@ public abstract class BSLinkset
277 return mass; 282 return mass;
278 } 283 }
279 284
285 // Computes linkset's center of mass in world coordinates.
280 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() 286 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
281 { 287 {
282 OMV.Vector3 com; 288 OMV.Vector3 com;
@@ -285,7 +291,7 @@ public abstract class BSLinkset
285 com = LinksetRoot.Position * LinksetRoot.RawMass; 291 com = LinksetRoot.Position * LinksetRoot.RawMass;
286 float totalMass = LinksetRoot.RawMass; 292 float totalMass = LinksetRoot.RawMass;
287 293
288 foreach (BSPhysObject bp in m_children) 294 foreach (BSPrimLinkable bp in m_children)
289 { 295 {
290 com += bp.Position * bp.RawMass; 296 com += bp.Position * bp.RawMass;
291 totalMass += bp.RawMass; 297 totalMass += bp.RawMass;
@@ -304,9 +310,9 @@ public abstract class BSLinkset
304 { 310 {
305 com = LinksetRoot.Position; 311 com = LinksetRoot.Position;
306 312
307 foreach (BSPhysObject bp in m_children) 313 foreach (BSPrimLinkable 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..e05562a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,80 @@ 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 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
55 public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement)
56 {
57 // Each child position and rotation is given relative to the center-of-mass.
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 }
69 public override void Clear()
70 {
71 Index = 0;
72 OffsetFromRoot = OMV.Vector3.Zero;
73 OffsetFromCenterOfMass = OMV.Vector3.Zero;
74 OffsetRot = OMV.Quaternion.Identity;
75 }
76 public override string ToString()
77 {
78 StringBuilder buff = new StringBuilder();
79 buff.Append("<i=");
80 buff.Append(Index.ToString());
81 buff.Append(",p=");
82 buff.Append(OffsetFromRoot.ToString());
83 buff.Append(",m=");
84 buff.Append(OffsetFromCenterOfMass.ToString());
85 buff.Append(",r=");
86 buff.Append(OffsetRot.ToString());
87 buff.Append(">");
88 return buff.ToString();
89 }
90};
91
35public sealed class BSLinksetCompound : BSLinkset 92public sealed class BSLinksetCompound : BSLinkset
36{ 93{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 95
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
97 : base(scene, parent)
40 { 98 {
41 base.Initialize(scene, parent);
42 } 99 }
43 100
44 // For compound implimented linksets, if there are children, use compound shape for the root. 101 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
46 { 103 {
104 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 106 if (IsRoot(requestor) && HasAnyChildren)
49 { 107 {
@@ -55,41 +113,57 @@ public sealed class BSLinksetCompound : BSLinkset
55 113
56 // When physical properties are changed the linkset needs to recalculate 114 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 115 // its internal properties.
58 // This is queued in the 'post taint' queue so the 116 public override void Refresh(BSPrimLinkable requestor)
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 { 117 {
62 // External request for Refresh (from BSPrim) is not necessary 118 base.Refresh(requestor);
63 // InternalRefresh(requestor); 119
120 // Something changed so do the rebuilding thing
121 // ScheduleRebuild();
64 } 122 }
65 123
66 private void InternalRefresh(BSPhysObject requestor) 124 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor)
67 { 126 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
69 // Queue to happen after all the other taint processing 128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 129 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren)
71 { 133 {
72 if (IsRoot(requestor) && HasAnyChildren) 134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 135 {
74 }); 136 if (HasAnyChildren)
137 RecomputeLinksetCompound();
138 });
139 }
75 } 140 }
76 141
77 // The object is going dynamic (physical). Do any setup necessary 142 // 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 143 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 144 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 145 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time! 146 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child) 147 public override bool MakeDynamic(BSPrimLinkable child)
84 { 148 {
85 bool ret = false; 149 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 150 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 151 if (IsRoot(child))
152 {
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot);
155 }
156 else
88 { 157 {
89 // Physical children are removed from the world as the shape ofthe root compound 158 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 159 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
93 ret = true; 167 ret = true;
94 } 168 }
95 return ret; 169 return ret;
@@ -100,73 +174,181 @@ public sealed class BSLinksetCompound : BSLinkset
100 // This doesn't normally happen -- OpenSim removes the objects from the physical 174 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset. 175 // world if it is a static linkset.
102 // Called at taint-time! 176 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child) 177 public override bool MakeStatic(BSPrimLinkable child)
104 { 178 {
105 bool ret = false; 179 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 181 if (IsRoot(child))
182 {
183 ScheduleRebuild(LinksetRoot);
184 }
185 else
108 { 186 {
109 // The non-physical children can come back to life. 187 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 189
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 194 ret = true;
114 } 195 }
115 return ret; 196 return ret;
116 } 197 }
117 198
118 // Called at taint-time!! 199 // '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) 200 // Called at taint-time.
120 { 201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
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 { 202 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr); 203 // The user moving a child around requires the rebuilding of the linkset compound shape
129 } 204 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 {
211 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset.
213 // If a handle for the child can be fetch, we update the child here. If a rebuild was
214 // scheduled by someone else, the rebuild will just replace this setting.
215
216 bool updatedChild = false;
217 // Anything other than updating position or orientation usually means a physical update
218 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 {
221 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
223 {
224 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
230 if (updated.LinksetChildIndex < numLinksetChildren)
231 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape)
234 {
235 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */);
240 updatedChild = true;
241 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
242 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
243 }
244 else // DEBUG DEBUG
245 { // DEBUG DEBUG
246 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
247 updated.LocalID, linksetChildShape);
248 } // DEBUG DEBUG
249 }
250 else // DEBUG DEBUG
251 { // DEBUG DEBUG
252 // the child is not yet in the compound shape. This is non-fatal.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
254 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
255 } // DEBUG DEBUG
256 }
257 else // DEBUG DEBUG
258 { // DEBUG DEBUG
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
260 } // DEBUG DEBUG
130 261
131 public override OMV.Quaternion Orientation(BSPhysObject member) 262 if (!updatedChild)
132 { 263 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 264 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
265 // Note: there are several ways through this code that will not update the child if
266 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
267 // there will already be a rebuild scheduled.
268 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
269 updated.LocalID, whichUpdated);
270 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
271 ScheduleRebuild(updated);
272 }
273 }
274 }
134 } 275 }
135 276
136 // Routine called when rebuilding the body of some member of the linkset. 277 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing. 278 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring 279 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!! 280 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child) 281 public override bool RemoveBodyDependencies(BSPrimLinkable child)
141 { 282 {
142 bool ret = false; 283 bool ret = false;
143 284
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
146 287
147 if (!IsRoot(child)) 288 if (!IsRoot(child))
148 { 289 {
149 // Cause the current shape to be freed and the new one to be built. 290 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 291 // its position in the linkset.
151 ret = true; 292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
152 } 294 }
153 295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299
154 return ret; 300 return ret;
155 } 301 }
156 302
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 303 // When the linkset is built, the child shape is added to the compound shape relative to the
158 // this routine will restore the removed constraints. 304 // root shape. The linkset then moves around but this does not move the actual child
159 // Called at taint-time!! 305 // prim. The child prim's location must be recomputed based on the location of the root shape.
160 public override void RestoreBodyDependencies(BSPrim child) 306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
161 { 307 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
163 } 345 }
164 346
165 // ================================================================ 347 // ================================================================
166 348
167 // Add a new child to the linkset. 349 // Add a new child to the linkset.
168 // Called while LinkActivity is locked. 350 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child) 351 protected override void AddChildToLinkset(BSPrimLinkable child)
170 { 352 {
171 if (!HasChild(child)) 353 if (!HasChild(child))
172 { 354 {
@@ -174,24 +356,28 @@ public sealed class BSLinksetCompound : BSLinkset
174 356
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 357 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 358
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 359 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 360 ScheduleRebuild(child);
179 } 361 }
180 return; 362 return;
181 } 363 }
182 364
183 // Remove the specified child from the linkset. 365 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 366 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 367 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
186 { 368 {
369 child.ClearDisplacement();
370
187 if (m_children.Remove(child)) 371 if (m_children.Remove(child))
188 { 372 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 373 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 374 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 375 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 376 child.LocalID, child.PhysBody.AddrString);
193 377
194 // Cause the child's body to be rebuilt and thus restored to normal operation 378 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null;
195 child.ForceBodyShapeRebuild(false); 381 child.ForceBodyShapeRebuild(false);
196 382
197 if (!HasAnyChildren) 383 if (!HasAnyChildren)
@@ -201,8 +387,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 387 }
202 else 388 else
203 { 389 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 390 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 391 ScheduleRebuild(LinksetRoot);
206 } 392 }
207 } 393 }
208 return; 394 return;
@@ -213,63 +399,116 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 399 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 400 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 401 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged
216 private void RecomputeLinksetCompound() 403 private void RecomputeLinksetCompound()
217 { 404 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 405 try
219 LinksetRoot.ForceBodyShapeRebuild(true); 406 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true;
220 409
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 410 // Cause the root shape to be rebuilt as a compound object with just the root in it
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */);
223 412
224 // Add a shape for each of the other children in the linkset 413 // The center of mass for the linkset is the geometric center of the group.
225 ForEachMember(delegate(BSPhysObject cPrim) 414 // Compute a displacement for each component so it is relative to the center-of-mass.
226 { 415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
227 if (!IsRoot(cPrim)) 416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
228 { 418 {
229 // Each child position and rotation is given relative to the root. 419 // Compute a center-of-mass in world coordinates.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 420 centerOfMassW = ComputeLinksetCenterOfMass();
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 421 }
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 422
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
424
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
233 428
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 429 // This causes the physical position of the root prim to be offset to accomodate for the displacements
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
236 431
237 if (cPrim.PhysShape.isNativeShape) 432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
443
444 // Add a shape for each of the other children in the linkset
445 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim)
447 {
448 if (IsRoot(cPrim))
238 { 449 {
239 // Native shapes are not shared so we need to create a new one. 450 cPrim.LinksetChildIndex = 0;
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 } 451 }
249 else 452 else
250 { 453 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 454 cPrim.LinksetChildIndex = memberIndex;
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 455
456 if (cPrim.PhysShape.isNativeShape)
253 { 457 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 458 // A native shape is turned into a hull collision shape because native
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
256 } 475 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); 476 else
258 } 477 {
259 } 478 // For the shared shapes (meshes and hulls), just use the shape in the child.
260 return false; // 'false' says to move onto the next child in the list 479 // The reference count added here will be decremented when the compound shape
261 }); 480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
262 491
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 492 }
264 float linksetMass = LinksetMass; 493 memberIndex++;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 494 }
495 return false; // 'false' says to move onto the next child in the list
496 });
266 497
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 498 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
268 501
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 502 // Enable the physical position updator to return the position and rotation of the root shape
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 504 }
505 finally
506 {
507 Rebuilding = false;
508 }
272 509
510 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 512 }
274} 513}
275} \ No newline at end of file 514} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..6d252ca 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,23 +36,27 @@ 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, BSPrimLinkable 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
45 // its internal properties. 44 // its internal properties.
46 // This is queued in the 'post taint' queue so the 45 // This is queued in the 'post taint' queue so the
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(BSPrimLinkable 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
@@ -61,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset
61 // has not yet been fully constructed. 65 // has not yet been fully constructed.
62 // Return 'true' if any properties updated on the passed object. 66 // Return 'true' if any properties updated on the passed object.
63 // Called at taint-time! 67 // Called at taint-time!
64 public override bool MakeDynamic(BSPhysObject child) 68 public override bool MakeDynamic(BSPrimLinkable child)
65 { 69 {
66 // What is done for each object in BSPrim is what we want. 70 // What is done for each object in BSPrim is what we want.
67 return false; 71 return false;
@@ -72,41 +76,29 @@ public sealed class BSLinksetConstraints : BSLinkset
72 // This doesn't normally happen -- OpenSim removes the objects from the physical 76 // This doesn't normally happen -- OpenSim removes the objects from the physical
73 // world if it is a static linkset. 77 // world if it is a static linkset.
74 // Called at taint-time! 78 // Called at taint-time!
75 public override bool MakeStatic(BSPhysObject child) 79 public override bool MakeStatic(BSPrimLinkable child)
76 { 80 {
77 // What is done for each object in BSPrim is what we want. 81 // What is done for each object in BSPrim is what we want.
78 return false; 82 return false;
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(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
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.
102 // Returns 'true' of something was actually removed and would need restoring 94 // Returns 'true' of something was actually removed and would need restoring
103 // Called at taint-time!! 95 // Called at taint-time!!
104 public override bool RemoveBodyDependencies(BSPrim child) 96 public override bool RemoveBodyDependencies(BSPrimLinkable child)
105 { 97 {
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 {
@@ -118,19 +110,11 @@ public sealed class BSLinksetConstraints : BSLinkset
118 return ret; 110 return ret;
119 } 111 }
120 112
121 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
122 // this routine will restore the removed constraints.
123 // Called at taint-time!!
124 public override void RestoreBodyDependencies(BSPrim child)
125 {
126 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
127 }
128
129 // ================================================================ 113 // ================================================================
130 114
131 // Add a new child to the linkset. 115 // Add a new child to the linkset.
132 // Called while LinkActivity is locked. 116 // Called while LinkActivity is locked.
133 protected override void AddChildToLinkset(BSPhysObject child) 117 protected override void AddChildToLinkset(BSPrimLinkable child)
134 { 118 {
135 if (!HasChild(child)) 119 if (!HasChild(child))
136 { 120 {
@@ -146,17 +130,17 @@ public sealed class BSLinksetConstraints : BSLinkset
146 130
147 // Remove the specified child from the linkset. 131 // Remove the specified child from the linkset.
148 // Safe to call even if the child is not really in my linkset. 132 // Safe to call even if the child is not really in my linkset.
149 protected override void RemoveChildFromLinkset(BSPhysObject child) 133 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
150 { 134 {
151 if (m_children.Remove(child)) 135 if (m_children.Remove(child))
152 { 136 {
153 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now 137 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
154 BSPhysObject childx = child; 138 BSPrimLinkable childx = child;
155 139
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 140 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID, 141 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), 142 rootx.LocalID, rootx.PhysBody.AddrString,
159 childx.LocalID, childx.PhysBody.ptr.ToString("X")); 143 childx.LocalID, childx.PhysBody.AddrString);
160 144
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 145 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 { 146 {
@@ -175,13 +159,13 @@ public sealed class BSLinksetConstraints : BSLinkset
175 159
176 // Create a constraint between me (root of linkset) and the passed prim (the child). 160 // Create a constraint between me (root of linkset) and the passed prim (the child).
177 // Called at taint time! 161 // Called at taint time!
178 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 162 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
179 { 163 {
180 // Don't build the constraint when asked. Put it off until just before the simulation step. 164 // Don't build the constraint when asked. Put it off until just before the simulation step.
181 Refresh(rootPrim); 165 Refresh(rootPrim);
182 } 166 }
183 167
184 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) 168 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
185 { 169 {
186 // Zero motion for children so they don't interpolate 170 // Zero motion for children so they don't interpolate
187 childPrim.ZeroMotion(true); 171 childPrim.ZeroMotion(true);
@@ -195,8 +179,8 @@ public sealed class BSLinksetConstraints : BSLinkset
195 179
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 180 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID, 181 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 182 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), 183 childPrim.LocalID, childPrim.PhysBody.AddrString,
200 rootPrim.Position, childPrim.Position, midPoint); 184 rootPrim.Position, childPrim.Position, midPoint);
201 185
202 // create a constraint that allows no freedom of movement between the two objects 186 // create a constraint that allows no freedom of movement between the two objects
@@ -239,14 +223,14 @@ public sealed class BSLinksetConstraints : BSLinkset
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 223 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240 224
241 // tweek the constraint to increase stability 225 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); 226 constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), 227 constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 228 BSParam.LinkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 229 BSParam.LinkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 230 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) 231 if (BSParam.LinkConstraintSolverIterations != 0f)
248 { 232 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 233 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
250 } 234 }
251 return constrain; 235 return constrain;
252 } 236 }
@@ -255,19 +239,19 @@ public sealed class BSLinksetConstraints : BSLinkset
255 // The root and child bodies are passed in because we need to remove the constraint between 239 // The root and child bodies are passed in because we need to remove the constraint between
256 // the bodies that were present at unlink time. 240 // the bodies that were present at unlink time.
257 // Called at taint time! 241 // Called at taint time!
258 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 242 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
259 { 243 {
260 bool ret = false; 244 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 245 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID, 246 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 247 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); 248 childPrim.LocalID, childPrim.PhysBody.AddrString);
265 249
266 // Find the constraint for this link and get rid of it from the overall collection and from my list 250 // 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)) 251 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 { 252 {
269 // Make the child refresh its location 253 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); 254 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
271 ret = true; 255 ret = true;
272 } 256 }
273 257
@@ -277,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset
277 // Remove linkage between myself and any possible children I might have. 261 // Remove linkage between myself and any possible children I might have.
278 // Returns 'true' of any constraints were destroyed. 262 // Returns 'true' of any constraints were destroyed.
279 // Called at taint time! 263 // Called at taint time!
280 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 264 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
281 { 265 {
282 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
283 267
@@ -292,20 +276,17 @@ public sealed class BSLinksetConstraints : BSLinkset
292 private void RecomputeLinksetConstraints() 276 private void RecomputeLinksetConstraints()
293 { 277 {
294 float linksetMass = LinksetMass; 278 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 279 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
296 280
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}", 281 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); 282 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
302 283
303 foreach (BSPhysObject child in m_children) 284 foreach (BSPrimLinkable child in m_children)
304 { 285 {
305 // A child in the linkset physically shows the mass of the whole linkset. 286 // 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. 287 // 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.) 288 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass); 289 child.UpdatePhysicalMassProperties(linksetMass, true);
309 290
310 BSConstraint constrain; 291 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 292 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
@@ -315,11 +296,7 @@ public sealed class BSLinksetConstraints : BSLinkset
315 } 296 }
316 constrain.RecomputeConstraintVariables(linksetMass); 297 constrain.RecomputeConstraintVariables(linksetMass);
317 298
318 // DEBUG: see of inter-linkset collisions are causing problems 299 // 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 } 300 }
324 301
325 } 302 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..ee77d6e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,203 @@
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 // Get the current attribute values for this material
184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
187 if (fieldInfo != null)
188 {
189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
191 Attributes[matType] = thisAttrib;
192 }
193 }
194
195 // Given a material type, return a structure of attributes.
196 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
197 {
198 int ind = (int)type;
199 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
200 return Attributes[ind];
201 }
202}
203}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..9501e2d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,486 @@
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 // Returns the correction needed to move 'current' to 'target'.
143 public virtual Vector3 Step(float timeStep)
144 {
145 if (!Enabled) return TargetValue;
146
147 Vector3 origTarget = TargetValue; // DEBUG
148 Vector3 origCurrVal = CurrentValue; // DEBUG
149
150 Vector3 correction = Vector3.Zero;
151 Vector3 error = TargetValue - CurrentValue;
152 LastError = error;
153 if (!ErrorIsZero(error))
154 {
155 correction = StepError(timeStep, error);
156
157 CurrentValue += correction;
158
159 // The desired value reduces to zero which also reduces the difference with current.
160 // If the decay time is infinite, don't decay at all.
161 float decayFactor = 0f;
162 if (TargetValueDecayTimeScale != BSMotor.Infinite)
163 {
164 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
165 TargetValue *= (1f - decayFactor);
166 }
167
168 // The amount we can correct the error is reduced by the friction
169 Vector3 frictionFactor = Vector3.Zero;
170 if (FrictionTimescale != BSMotor.InfiniteVector)
171 {
172 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
173 // Individual friction components can be 'infinite' so compute each separately.
174 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
175 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
176 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
177 frictionFactor *= timeStep;
178 CurrentValue *= (Vector3.One - frictionFactor);
179 }
180
181 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
182 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
183 timeStep, error, correction);
184 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
185 BSScene.DetailLogZero, UseName,
186 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
187 TargetValue, CurrentValue);
188 }
189 else
190 {
191 // Difference between what we have and target is small. Motor is done.
192 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
193 {
194 // The target can step down to nearly zero but not get there. If close to zero
195 // it is really zero.
196 TargetValue = Vector3.Zero;
197 }
198 CurrentValue = TargetValue;
199 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
200 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
201 }
202
203 return correction;
204 }
205 // version of step that sets the current value before doing the step
206 public virtual Vector3 Step(float timeStep, Vector3 current)
207 {
208 CurrentValue = current;
209 return Step(timeStep);
210 }
211 public virtual Vector3 StepError(float timeStep, Vector3 error)
212 {
213 if (!Enabled) return Vector3.Zero;
214
215 Vector3 returnCorrection = Vector3.Zero;
216 if (!ErrorIsZero(error))
217 {
218 // correction = error / secondsItShouldTakeToCorrect
219 Vector3 correctionAmount;
220 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
221 correctionAmount = error * timeStep;
222 else
223 correctionAmount = error / TimeScale * timeStep;
224
225 returnCorrection = correctionAmount;
226 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
227 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
228 }
229 return returnCorrection;
230 }
231
232 // The user sets all the parameters and calls this which outputs values until error is zero.
233 public override void GenerateTestOutput(float timeStep)
234 {
235 // maximum number of outputs to generate.
236 int maxOutput = 50;
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
239 BSScene.DetailLogZero, UseName,
240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
241 CurrentValue, TargetValue);
242
243 LastError = BSMotor.InfiniteVector;
244 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
245 {
246 Vector3 lastStep = Step(timeStep);
247 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
249 }
250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
251
252
253 }
254
255 public override string ToString()
256 {
257 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
258 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
259 }
260}
261
262// ============================================================================
263// ============================================================================
264public class BSFMotor : BSMotor
265{
266 public virtual float TimeScale { get; set; }
267 public virtual float TargetValueDecayTimeScale { get; set; }
268 public virtual float FrictionTimescale { get; set; }
269 public virtual float Efficiency { get; set; }
270
271 public virtual float ErrorZeroThreshold { get; set; }
272
273 public virtual float TargetValue { get; protected set; }
274 public virtual float CurrentValue { get; protected set; }
275 public virtual float LastError { get; protected set; }
276
277 public virtual bool ErrorIsZero()
278 {
279 return ErrorIsZero(LastError);
280 }
281 public virtual bool ErrorIsZero(float err)
282 {
283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
284 }
285
286 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
287 : base(useName)
288 {
289 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
290 Efficiency = 1f;
291 FrictionTimescale = BSMotor.Infinite;
292 CurrentValue = TargetValue = 0f;
293 ErrorZeroThreshold = 0.01f;
294 }
295 public void SetCurrent(float current)
296 {
297 CurrentValue = current;
298 }
299 public void SetTarget(float target)
300 {
301 TargetValue = target;
302 }
303 public override void Zero()
304 {
305 base.Zero();
306 CurrentValue = TargetValue = 0f;
307 }
308
309 public virtual float Step(float timeStep)
310 {
311 if (!Enabled) return TargetValue;
312
313 float origTarget = TargetValue; // DEBUG
314 float origCurrVal = CurrentValue; // DEBUG
315
316 float correction = 0f;
317 float error = TargetValue - CurrentValue;
318 LastError = error;
319 if (!ErrorIsZero(error))
320 {
321 correction = StepError(timeStep, error);
322
323 CurrentValue += correction;
324
325 // The desired value reduces to zero which also reduces the difference with current.
326 // If the decay time is infinite, don't decay at all.
327 float decayFactor = 0f;
328 if (TargetValueDecayTimeScale != BSMotor.Infinite)
329 {
330 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
331 TargetValue *= (1f - decayFactor);
332 }
333
334 // The amount we can correct the error is reduced by the friction
335 float frictionFactor = 0f;
336 if (FrictionTimescale != BSMotor.Infinite)
337 {
338 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
339 // Individual friction components can be 'infinite' so compute each separately.
340 frictionFactor = 1f / FrictionTimescale;
341 frictionFactor *= timeStep;
342 CurrentValue *= (1f - frictionFactor);
343 }
344
345 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
346 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
347 timeStep, error, correction);
348 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
349 BSScene.DetailLogZero, UseName,
350 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
351 TargetValue, CurrentValue);
352 }
353 else
354 {
355 // Difference between what we have and target is small. Motor is done.
356 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
357 {
358 // The target can step down to nearly zero but not get there. If close to zero
359 // it is really zero.
360 TargetValue = 0f;
361 }
362 CurrentValue = TargetValue;
363 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
364 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
365 }
366
367 return CurrentValue;
368 }
369
370 public virtual float StepError(float timeStep, float error)
371 {
372 if (!Enabled) return 0f;
373
374 float returnCorrection = 0f;
375 if (!ErrorIsZero(error))
376 {
377 // correction = error / secondsItShouldTakeToCorrect
378 float correctionAmount;
379 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
380 correctionAmount = error * timeStep;
381 else
382 correctionAmount = error / TimeScale * timeStep;
383
384 returnCorrection = correctionAmount;
385 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
386 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
387 }
388 return returnCorrection;
389 }
390
391 public override string ToString()
392 {
393 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
394 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
395 }
396
397}
398
399// ============================================================================
400// ============================================================================
401// Proportional, Integral, Derivitive Motor
402// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
403public class BSPIDVMotor : BSVMotor
404{
405 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
406 public Vector3 proportionFactor { get; set; }
407 public Vector3 integralFactor { get; set; }
408 public Vector3 derivFactor { get; set; }
409
410 // The factors are vectors for the three dimensions. This is the proportional of each
411 // that is applied. This could be multiplied through the actual factors but it
412 // is sometimes easier to manipulate the factors and their mix separately.
413 // to
414 public Vector3 FactorMix;
415
416 // Arbritrary factor range.
417 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
418 public float EfficiencyHigh = 0.4f;
419 public float EfficiencyLow = 4.0f;
420
421 // Running integration of the error
422 Vector3 RunningIntegration { get; set; }
423
424 public BSPIDVMotor(string useName)
425 : base(useName)
426 {
427 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
428 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
429 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
430 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
431 RunningIntegration = Vector3.Zero;
432 LastError = Vector3.Zero;
433 }
434
435 public override void Zero()
436 {
437 base.Zero();
438 }
439
440 public override float Efficiency
441 {
442 get { return base.Efficiency; }
443 set
444 {
445 base.Efficiency = Util.Clamp(value, 0f, 1f);
446
447 // Compute factors based on efficiency.
448 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
449 // If efficiency is low (0f), use a factor value that overcorrects.
450 // TODO: might want to vary contribution of different factor depending on efficiency.
451 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
452 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
453
454 proportionFactor = new Vector3(factor, factor, factor);
455 integralFactor = new Vector3(factor, factor, factor);
456 derivFactor = new Vector3(factor, factor, factor);
457
458 MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
459 }
460 }
461
462 // Advance the PID computation on this error.
463 public override Vector3 StepError(float timeStep, Vector3 error)
464 {
465 if (!Enabled) return Vector3.Zero;
466
467 // Add up the error so we can integrate over the accumulated errors
468 RunningIntegration += error * timeStep;
469
470 // A simple derivitive is the rate of change from the last error.
471 Vector3 derivitive = (error - LastError) * timeStep;
472 LastError = error;
473
474 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
475 Vector3 ret = error * timeStep * proportionFactor * FactorMix.X
476 + RunningIntegration * integralFactor * FactorMix.Y
477 + derivitive * derivFactor * FactorMix.Z
478 ;
479
480 MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}",
481 BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret);
482
483 return ret;
484 }
485}
486}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
new file mode 100755
index 0000000..385ed9e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -0,0 +1,815 @@
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 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41
42 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
44 // Contact points can be added even if the distance is positive. The constraint solver can deal with
45 // contacts with positive distances as well as negative (penetration). Contact points are discarded
46 // if the distance exceeds a certain threshold.
47 // Bullet has a contact processing threshold and a contact breaking threshold.
48 // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
49 // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
50
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy.
53 // ===================
54 // From:
55
56 // Level of Detail values kept as float because that's what the Meshmerizer wants
57 public static float MeshLOD { get; private set; }
58 public static float MeshCircularLOD { get; private set; }
59 public static float MeshMegaPrimLOD { get; private set; }
60 public static float MeshMegaPrimThreshold { get; private set; }
61 public static float SculptLOD { get; private set; }
62
63 public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
64 public static float UpdateVelocityChangeThreshold { get; private set; }
65
66 public static float MinimumObjectMass { get; private set; }
67 public static float MaximumObjectMass { get; private set; }
68 public static float MaxLinearVelocity { get; private set; }
69 public static float MaxLinearVelocitySquared { get; private set; }
70 public static float MaxAngularVelocity { get; private set; }
71 public static float MaxAngularVelocitySquared { get; private set; }
72 public static float MaxAddForceMagnitude { get; private set; }
73 public static float MaxAddForceMagnitudeSquared { get; private set; }
74 public static float DensityScaleFactor { get; private set; }
75
76 public static float LinearDamping { get; private set; }
77 public static float AngularDamping { get; private set; }
78 public static float DeactivationTime { get; private set; }
79 public static float LinearSleepingThreshold { get; private set; }
80 public static float AngularSleepingThreshold { get; private set; }
81 public static float CcdMotionThreshold { get; private set; }
82 public static float CcdSweptSphereRadius { get; private set; }
83 public static float ContactProcessingThreshold { get; private set; }
84
85 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
86 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
89
90 public static float TerrainImplementation { get; private set; }
91 public static int TerrainMeshMagnification { get; private set; }
92 public static float TerrainFriction { get; private set; }
93 public static float TerrainHitFraction { get; private set; }
94 public static float TerrainRestitution { get; private set; }
95 public static float TerrainContactProcessingThreshold { get; private set; }
96 public static float TerrainCollisionMargin { get; private set; }
97
98 public static float DefaultFriction { get; private set; }
99 public static float DefaultDensity { get; private set; }
100 public static float DefaultRestitution { get; private set; }
101 public static float CollisionMargin { get; private set; }
102 public static float Gravity { get; private set; }
103
104 // Physics Engine operation
105 public static float MaxPersistantManifoldPoolSize { get; private set; }
106 public static float MaxCollisionAlgorithmPoolSize { get; private set; }
107 public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
108 public static bool ShouldForceUpdateAllAabbs { get; private set; }
109 public static bool ShouldRandomizeSolverOrder { get; private set; }
110 public static bool ShouldSplitSimulationIslands { get; private set; }
111 public static bool ShouldEnableFrictionCaching { get; private set; }
112 public static float NumberOfSolverIterations { get; private set; }
113 public static bool UseSingleSidedMeshes { get; private set; }
114 public static float GlobalContactBreakingThreshold { get; private set; }
115
116 // Avatar parameters
117 public static float AvatarFriction { get; private set; }
118 public static float AvatarStandingFriction { get; private set; }
119 public static float AvatarAlwaysRunFactor { get; private set; }
120 public static float AvatarDensity { get; private set; }
121 public static float AvatarRestitution { get; private set; }
122 public static float AvatarCapsuleWidth { get; private set; }
123 public static float AvatarCapsuleDepth { get; private set; }
124 public static float AvatarCapsuleHeight { get; private set; }
125 public static float AvatarContactProcessingThreshold { get; private set; }
126 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
127 public static float AvatarStepHeight { get; private set; }
128 public static float AvatarStepApproachFactor { get; private set; }
129 public static float AvatarStepForceFactor { get; private set; }
130
131 // Vehicle parameters
132 public static float VehicleMaxLinearVelocity { get; private set; }
133 public static float VehicleMaxLinearVelocitySquared { get; private set; }
134 public static float VehicleMaxAngularVelocity { get; private set; }
135 public static float VehicleMaxAngularVelocitySq { get; private set; }
136 public static float VehicleAngularDamping { get; private set; }
137 public static float VehicleFriction { get; private set; }
138 public static float VehicleRestitution { get; private set; }
139 public static Vector3 VehicleLinearFactor { get; private set; }
140 public static Vector3 VehicleAngularFactor { get; private set; }
141 public static float VehicleGroundGravityFudge { get; private set; }
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; }
144
145 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; }
147 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
148 public static float CSHullConcavityThresholdPercent { get; private set; }
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; }
152
153 // Linkset implementation parameters
154 public static float LinksetImplementation { get; private set; }
155 public static bool LinkConstraintUseFrameOffset { get; private set; }
156 public static bool LinkConstraintEnableTransMotor { get; private set; }
157 public static float LinkConstraintTransMotorMaxVel { get; private set; }
158 public static float LinkConstraintTransMotorMaxForce { get; private set; }
159 public static float LinkConstraintERP { get; private set; }
160 public static float LinkConstraintCFM { get; private set; }
161 public static float LinkConstraintSolverIterations { get; private set; }
162
163 public static float PID_D { get; private set; } // derivative
164 public static float PID_P { get; private set; } // proportional
165
166 // Various constants that come from that other virtual world that shall not be named.
167 public const float MinGravityZ = -1f;
168 public const float MaxGravityZ = 28f;
169 public const float MinFriction = 0f;
170 public const float MaxFriction = 255f;
171 public const float MinDensity = 0.01f;
172 public const float MaxDensity = 22587f;
173 public const float MinRestitution = 0f;
174 public const float MaxRestitution = 1f;
175
176 // =====================================================================================
177 // =====================================================================================
178
179 // Base parameter definition that gets and sets parameter values via a string
180 public abstract class ParameterDefnBase
181 {
182 public string name; // string name of the parameter
183 public string desc; // a short description of what the parameter means
184 public ParameterDefnBase(string pName, string pDesc)
185 {
186 name = pName;
187 desc = pDesc;
188 }
189 // Set the parameter value to the default
190 public abstract void AssignDefault(BSScene s);
191 // Get the value as a string
192 public abstract string GetValue(BSScene s);
193 // Set the value to this string value
194 public abstract void SetValue(BSScene s, string valAsString);
195 // set the value on a particular object (usually sets in physics engine)
196 public abstract void SetOnObject(BSScene s, BSPhysObject obj);
197 public abstract bool HasSetOnObject { get; }
198 }
199
200 // Specific parameter definition for a parameter of a specific type.
201 public delegate T PGetValue<T>(BSScene s);
202 public delegate void PSetValue<T>(BSScene s, T val);
203 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
204 public sealed class ParameterDefn<T> : ParameterDefnBase
205 {
206 private T defaultValue;
207 private PSetValue<T> setter;
208 private PGetValue<T> getter;
209 private PSetOnObject<T> objectSet;
210 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
211 : base(pName, pDesc)
212 {
213 defaultValue = pDefault;
214 setter = pSetter;
215 getter = pGetter;
216 objectSet = null;
217 }
218 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter)
219 : base(pName, pDesc)
220 {
221 defaultValue = pDefault;
222 setter = pSetter;
223 getter = pGetter;
224 objectSet = pObjSetter;
225 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
228 : base(pName, pDesc)
229 {
230 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; };
232 getter = (s) => { return loc; };
233 objectSet = null;
234 }
235 */
236 public override void AssignDefault(BSScene s)
237 {
238 setter(s, defaultValue);
239 }
240 public override string GetValue(BSScene s)
241 {
242 return getter(s).ToString();
243 }
244 public override void SetValue(BSScene s, string valAsString)
245 {
246 // Get the generic type of the setter
247 Type genericType = setter.GetType().GetGenericArguments()[0];
248 // Find the 'Parse' method on that type
249 System.Reflection.MethodInfo parser = null;
250 try
251 {
252 parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
253 }
254 catch (Exception e)
255 {
256 s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
257 parser = null;
258 }
259 if (parser != null)
260 {
261 // Parse the input string
262 try
263 {
264 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
265 // Store the parsed value
266 setter(s, setValue);
267 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
268 }
269 catch
270 {
271 s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
272 }
273 }
274 else
275 {
276 s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
277 }
278 }
279 public override bool HasSetOnObject
280 {
281 get { return objectSet != null; }
282 }
283 public override void SetOnObject(BSScene s, BSPhysObject obj)
284 {
285 if (objectSet != null)
286 objectSet(s, obj);
287 }
288 }
289
290 // List of all of the externally visible parameters.
291 // For each parameter, this table maps a text name to getter and setters.
292 // To add a new externally referencable/settable parameter, add the paramter storage
293 // location somewhere in the program and make an entry in this table with the
294 // getters and setters.
295 // It is easiest to find an existing definition and copy it.
296 //
297 // A ParameterDefn<T>() takes the following parameters:
298 // -- the text name of the parameter. This is used for console input and ini file.
299 // -- a short text description of the parameter. This shows up in the console listing.
300 // -- a default value
301 // -- a delegate for getting the value
302 // -- a delegate for setting the value
303 // -- an optional delegate to update the value in the world. Most often used to
304 // push the new value to an in-world object.
305 //
306 // The single letter parameters for the delegates are:
307 // s = BSScene
308 // o = BSPhysObject
309 // v = value (appropriate type)
310 private static ParameterDefnBase[] ParameterDefinitions =
311 {
312 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
313 true,
314 (s) => { return ShouldMeshSculptedPrim; },
315 (s,v) => { ShouldMeshSculptedPrim = v; } ),
316 new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
317 false,
318 (s) => { return ShouldForceSimplePrimMeshing; },
319 (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
320 new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
321 true,
322 (s) => { return ShouldUseHullsForPhysicalObjects; },
323 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
324 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
325 true,
326 (s) => { return ShouldRemoveZeroWidthTriangles; },
327 (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ),
328
329 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
330 5,
331 (s) => { return CrossingFailuresBeforeOutOfBounds; },
332 (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ),
333 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
334 0.1f,
335 (s) => { return UpdateVelocityChangeThreshold; },
336 (s,v) => { UpdateVelocityChangeThreshold = v; } ),
337
338 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
339 32f,
340 (s) => { return MeshLOD; },
341 (s,v) => { MeshLOD = v; } ),
342 new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
343 32f,
344 (s) => { return MeshCircularLOD; },
345 (s,v) => { MeshCircularLOD = v; } ),
346 new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
347 10f,
348 (s) => { return MeshMegaPrimThreshold; },
349 (s,v) => { MeshMegaPrimThreshold = v; } ),
350 new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
351 32f,
352 (s) => { return MeshMegaPrimLOD; },
353 (s,v) => { MeshMegaPrimLOD = v; } ),
354 new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
355 32f,
356 (s) => { return SculptLOD; },
357 (s,v) => { SculptLOD = v; } ),
358
359 new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps",
360 10,
361 (s) => { return s.m_maxSubSteps; },
362 (s,v) => { s.m_maxSubSteps = (int)v; } ),
363 new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
364 1f / 60f,
365 (s) => { return s.m_fixedTimeStep; },
366 (s,v) => { s.m_fixedTimeStep = v; } ),
367 new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim",
368 55f,
369 (s) => { return s.NominalFrameRate; },
370 (s,v) => { s.NominalFrameRate = (int)v; } ),
371 new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
372 2048,
373 (s) => { return s.m_maxCollisionsPerFrame; },
374 (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
375 new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
376 8000,
377 (s) => { return s.m_maxUpdatesPerFrame; },
378 (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
379
380 new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)",
381 0.0001f,
382 (s) => { return MinimumObjectMass; },
383 (s,v) => { MinimumObjectMass = v; } ),
384 new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)",
385 10000.01f,
386 (s) => { return MaximumObjectMass; },
387 (s,v) => { MaximumObjectMass = v; } ),
388 new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
389 1000.0f,
390 (s) => { return MaxLinearVelocity; },
391 (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
392 new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
393 1000.0f,
394 (s) => { return MaxAngularVelocity; },
395 (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
396 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
397 new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
398 20000.0f,
399 (s) => { return MaxAddForceMagnitude; },
400 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
401 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
402 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
403 0.01f,
404 (s) => { return DensityScaleFactor; },
405 (s,v) => { DensityScaleFactor = v; } ),
406
407 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
408 2200f,
409 (s) => { return (float)PID_D; },
410 (s,v) => { PID_D = v; } ),
411 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
412 900f,
413 (s) => { return (float)PID_P; },
414 (s,v) => { PID_P = v; } ),
415
416 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
417 0.2f,
418 (s) => { return DefaultFriction; },
419 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
420 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
421 10.000006836f, // Aluminum g/cm3
422 (s) => { return DefaultDensity; },
423 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
424 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
425 0f,
426 (s) => { return DefaultRestitution; },
427 (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
428 new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
429 0.04f,
430 (s) => { return CollisionMargin; },
431 (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
432 new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)",
433 -9.80665f,
434 (s) => { return Gravity; },
435 (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
436 (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
437
438
439 new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
440 0f,
441 (s) => { return LinearDamping; },
442 (s,v) => { LinearDamping = v; },
443 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
444 new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
445 0f,
446 (s) => { return AngularDamping; },
447 (s,v) => { AngularDamping = v; },
448 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
449 new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static",
450 0.2f,
451 (s) => { return DeactivationTime; },
452 (s,v) => { DeactivationTime = v; },
453 (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
454 new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
455 0.8f,
456 (s) => { return LinearSleepingThreshold; },
457 (s,v) => { LinearSleepingThreshold = v;},
458 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
459 new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
460 1.0f,
461 (s) => { return AngularSleepingThreshold; },
462 (s,v) => { AngularSleepingThreshold = v;},
463 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
464 new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
465 0.0f, // set to zero to disable
466 (s) => { return CcdMotionThreshold; },
467 (s,v) => { CcdMotionThreshold = v;},
468 (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
469 new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
470 0.2f,
471 (s) => { return CcdSweptSphereRadius; },
472 (s,v) => { CcdSweptSphereRadius = v;},
473 (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
474 new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
475 0.0f,
476 (s) => { return ContactProcessingThreshold; },
477 (s,v) => { ContactProcessingThreshold = v;},
478 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
479
480 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
481 (float)BSTerrainPhys.TerrainImplementation.Mesh,
482 (s) => { return TerrainImplementation; },
483 (s,v) => { TerrainImplementation = v; } ),
484 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
485 2,
486 (s) => { return TerrainMeshMagnification; },
487 (s,v) => { TerrainMeshMagnification = v; } ),
488 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
489 0.3f,
490 (s) => { return TerrainFriction; },
491 (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
492 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
493 0.8f,
494 (s) => { return TerrainHitFraction; },
495 (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
496 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
497 0f,
498 (s) => { return TerrainRestitution; },
499 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
500 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
501 0.0f,
502 (s) => { return TerrainContactProcessingThreshold; },
503 (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
504 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
505 0.08f,
506 (s) => { return TerrainCollisionMargin; },
507 (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
508
509 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
510 0.2f,
511 (s) => { return AvatarFriction; },
512 (s,v) => { AvatarFriction = v; } ),
513 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
514 0.95f,
515 (s) => { return AvatarStandingFriction; },
516 (s,v) => { AvatarStandingFriction = v; } ),
517 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
518 1.3f,
519 (s) => { return AvatarAlwaysRunFactor; },
520 (s,v) => { AvatarAlwaysRunFactor = v; } ),
521 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
522 3.5f,
523 (s) => { return AvatarDensity; },
524 (s,v) => { AvatarDensity = v; } ),
525 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
526 0f,
527 (s) => { return AvatarRestitution; },
528 (s,v) => { AvatarRestitution = v; } ),
529 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
530 0.6f,
531 (s) => { return AvatarCapsuleWidth; },
532 (s,v) => { AvatarCapsuleWidth = v; } ),
533 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
534 0.45f,
535 (s) => { return AvatarCapsuleDepth; },
536 (s,v) => { AvatarCapsuleDepth = v; } ),
537 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
538 1.5f,
539 (s) => { return AvatarCapsuleHeight; },
540 (s,v) => { AvatarCapsuleHeight = v; } ),
541 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
542 0.1f,
543 (s) => { return AvatarContactProcessingThreshold; },
544 (s,v) => { AvatarContactProcessingThreshold = v; } ),
545 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
546 1.0f,
547 (s) => { return AvatarBelowGroundUpCorrectionMeters; },
548 (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ),
549 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
550 0.3f,
551 (s) => { return AvatarStepHeight; },
552 (s,v) => { AvatarStepHeight = v; } ),
553 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
554 0.6f,
555 (s) => { return AvatarStepApproachFactor; },
556 (s,v) => { AvatarStepApproachFactor = v; } ),
557 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
558 2.0f,
559 (s) => { return AvatarStepForceFactor; },
560 (s,v) => { AvatarStepForceFactor = v; } ),
561
562 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
563 1000.0f,
564 (s) => { return (float)VehicleMaxLinearVelocity; },
565 (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
566 new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
567 12.0f,
568 (s) => { return (float)VehicleMaxAngularVelocity; },
569 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
570 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
571 0.0f,
572 (s) => { return VehicleAngularDamping; },
573 (s,v) => { VehicleAngularDamping = v; } ),
574 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
575 new Vector3(1f, 1f, 1f),
576 (s) => { return VehicleLinearFactor; },
577 (s,v) => { VehicleLinearFactor = v; } ),
578 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
579 new Vector3(1f, 1f, 1f),
580 (s) => { return VehicleAngularFactor; },
581 (s,v) => { VehicleAngularFactor = v; } ),
582 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
583 0.0f,
584 (s) => { return VehicleFriction; },
585 (s,v) => { VehicleFriction = v; } ),
586 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
587 0.0f,
588 (s) => { return VehicleRestitution; },
589 (s,v) => { VehicleRestitution = v; } ),
590 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
591 0.2f,
592 (s) => { return VehicleGroundGravityFudge; },
593 (s,v) => { VehicleGroundGravityFudge = v; } ),
594 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
595 60.0f,
596 (s) => { return VehicleAngularBankingTimescaleFudge; },
597 (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
598 new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
599 false,
600 (s) => { return VehicleDebuggingEnabled; },
601 (s,v) => { VehicleDebuggingEnabled = v; } ),
602
603 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
604 0f,
605 (s) => { return MaxPersistantManifoldPoolSize; },
606 (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
607 new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
608 0f,
609 (s) => { return MaxCollisionAlgorithmPoolSize; },
610 (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
611 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
612 false,
613 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
614 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
615 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
616 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
617 false,
618 (s) => { return ShouldForceUpdateAllAabbs; },
619 (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
620 new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
621 true,
622 (s) => { return ShouldRandomizeSolverOrder; },
623 (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
624 new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
625 true,
626 (s) => { return ShouldSplitSimulationIslands; },
627 (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
628 new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching",
629 true,
630 (s) => { return ShouldEnableFrictionCaching; },
631 (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
632 new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
633 0f, // zero says use Bullet default
634 (s) => { return NumberOfSolverIterations; },
635 (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
636 new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
637 true,
638 (s) => { return UseSingleSidedMeshes; },
639 (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
640 new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
641 0f,
642 (s) => { return GlobalContactBreakingThreshold; },
643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
644
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7,
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2,
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f,
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f,
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32,
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0,
667 (s) => { return CSHullMaxSkinWidth; },
668 (s,v) => { CSHullMaxSkinWidth = v; } ),
669
670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
671 (float)BSLinkset.LinksetImplementation.Compound,
672 (s) => { return LinksetImplementation; },
673 (s,v) => { LinksetImplementation = v; } ),
674 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
675 false,
676 (s) => { return LinkConstraintUseFrameOffset; },
677 (s,v) => { LinkConstraintUseFrameOffset = v; } ),
678 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
679 true,
680 (s) => { return LinkConstraintEnableTransMotor; },
681 (s,v) => { LinkConstraintEnableTransMotor = v; } ),
682 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
683 5.0f,
684 (s) => { return LinkConstraintTransMotorMaxVel; },
685 (s,v) => { LinkConstraintTransMotorMaxVel = v; } ),
686 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
687 0.1f,
688 (s) => { return LinkConstraintTransMotorMaxForce; },
689 (s,v) => { LinkConstraintTransMotorMaxForce = v; } ),
690 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
691 0.1f,
692 (s) => { return LinkConstraintCFM; },
693 (s,v) => { LinkConstraintCFM = v; } ),
694 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
695 0.1f,
696 (s) => { return LinkConstraintERP; },
697 (s,v) => { LinkConstraintERP = v; } ),
698 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
699 40,
700 (s) => { return LinkConstraintSolverIterations; },
701 (s,v) => { LinkConstraintSolverIterations = v; } ),
702
703 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
704 0,
705 (s) => { return s.PhysicsMetricDumpFrames; },
706 (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
707 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
708 0f,
709 (s) => { return 0f; },
710 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
711 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
712 0f,
713 (s) => { return 0f; },
714 (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
715 };
716
717 // Convert a boolean to our numeric true and false values
718 public static float NumericBool(bool b)
719 {
720 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
721 }
722
723 // Convert numeric true and false values to a boolean
724 public static bool BoolNumeric(float b)
725 {
726 return (b == ConfigurationParameters.numericTrue ? true : false);
727 }
728
729 // Search through the parameter definitions and return the matching
730 // ParameterDefn structure.
731 // Case does not matter as names are compared after converting to lower case.
732 // Returns 'false' if the parameter is not found.
733 internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
734 {
735 bool ret = false;
736 ParameterDefnBase foundDefn = null;
737 string pName = paramName.ToLower();
738
739 foreach (ParameterDefnBase parm in ParameterDefinitions)
740 {
741 if (pName == parm.name.ToLower())
742 {
743 foundDefn = parm;
744 ret = true;
745 break;
746 }
747 }
748 defn = foundDefn;
749 return ret;
750 }
751
752 // Pass through the settable parameters and set the default values
753 internal static void SetParameterDefaultValues(BSScene physicsScene)
754 {
755 foreach (ParameterDefnBase parm in ParameterDefinitions)
756 {
757 parm.AssignDefault(physicsScene);
758 }
759 }
760
761 // Get user set values out of the ini file.
762 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
763 {
764 foreach (ParameterDefnBase parm in ParameterDefinitions)
765 {
766 parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
767 }
768 }
769
770 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
771
772 // This creates an array in the correct format for returning the list of
773 // parameters. This is used by the 'list' option of the 'physics' command.
774 internal static void BuildParameterTable()
775 {
776 if (SettableParameters.Length < ParameterDefinitions.Length)
777 {
778 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
779 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
780 {
781 ParameterDefnBase pd = ParameterDefinitions[ii];
782 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
783 }
784
785 // make the list alphabetical for ease of finding anything
786 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
787
788 SettableParameters = entries.ToArray();
789 }
790 }
791
792 // =====================================================================
793 // =====================================================================
794 // There are parameters that, when set, cause things to happen in the physics engine.
795 // This causes the broadphase collision cache to be cleared.
796 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
797 {
798 BSScene physScene = pPhysScene;
799 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
800 {
801 physScene.PE.ResetBroadphasePool(physScene.World);
802 });
803 }
804
805 // This causes the constraint solver cache to be cleared and reset.
806 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
807 {
808 BSScene physScene = pPhysScene;
809 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
810 {
811 physScene.PE.ResetConstraintSolver(physScene.World);
812 });
813 }
814}
815}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..6bb88c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,26 @@ 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
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
48public abstract class BSPhysObject : PhysicsActor 68public abstract class BSPhysObject : PhysicsActor
49{ 69{
50 protected BSPhysObject() 70 protected BSPhysObject()
@@ -55,15 +75,40 @@ public abstract class BSPhysObject : PhysicsActor
55 PhysicsScene = parentScene; 75 PhysicsScene = parentScene;
56 LocalID = localID; 76 LocalID = localID;
57 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
58 TypeName = typeName; 79 TypeName = typeName;
59 80
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 81 // Initialize variables kept in base.
61 LastAssetBuildFailed = false; 82 GravModifier = 1.0f;
83 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
84
85 // We don't have any physical representation yet.
86 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape();
88
89 PrimAssetState = PrimAssetCondition.Unknown;
90
91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood);
62 93
63 CollisionCollection = new CollisionEventUpdate(); 94 CollisionCollection = new CollisionEventUpdate();
95 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 96 SubscribedEventsMs = 0;
65 CollidingStep = 0; 97 CollidingStep = 0;
66 CollidingGroundStep = 0; 98 CollidingGroundStep = 0;
99 CollisionAccumulation = 0;
100 ColliderIsMoving = false;
101 CollisionScore = 0;
102
103 // All axis free.
104 LockedAxis = LockedAxisFree;
105 }
106
107 // Tell the object to clean up.
108 public virtual void Destroy()
109 {
110 UnRegisterAllPreStepActions();
111 UnRegisterAllPostStepActions();
67 } 112 }
68 113
69 public BSScene PhysicsScene { get; protected set; } 114 public BSScene PhysicsScene { get; protected set; }
@@ -71,13 +116,15 @@ public abstract class BSPhysObject : PhysicsActor
71 public string PhysObjectName { get; protected set; } 116 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 117 public string TypeName { get; protected set; }
73 118
74 public BSLinkset Linkset { get; set; }
75 119
76 // Return the object mass without calculating it or having side effects 120 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 121 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 122 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 123 // 'inWorld' true if the object has already been added to the dynamic world.
124 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 125
126 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
127 public virtual OMV.Vector3 Gravity { get; set; }
81 // The last value calculated for the prim's inertia 128 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 129 public OMV.Vector3 Inertia { get; set; }
83 130
@@ -86,12 +133,17 @@ public abstract class BSPhysObject : PhysicsActor
86 // Reference to the physical shape (btCollisionShape) of this object 133 // Reference to the physical shape (btCollisionShape) of this object
87 public BulletShape PhysShape; 134 public BulletShape PhysShape;
88 135
89 // 'true' if the mesh's underlying asset failed to build. 136 // The physical representation of the prim might require an asset fetch.
90 // This will keep us from looping after the first time the build failed. 137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
91 public bool LastAssetBuildFailed { get; set; } 138 public enum PrimAssetCondition
139 {
140 Unknown, Waiting, Failed, Fetched
141 }
142 public PrimAssetCondition PrimAssetState { get; set; }
92 143
93 // The objects base shape information. Null if not a prim type shape. 144 // The objects base shape information. Null if not a prim type shape.
94 public PrimitiveBaseShape BaseShape { get; protected set; } 145 public PrimitiveBaseShape BaseShape { get; protected set; }
146
95 // Some types of objects have preferred physical representations. 147 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference. 148 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape 149 public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -105,29 +157,46 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 157 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 158 public EntityProperties LastEntityProperties { get; set; }
107 159
108 public abstract OMV.Vector3 Scale { get; set; } 160 public virtual OMV.Vector3 Scale { get; set; }
161
162 // It can be confusing for an actor to know if it should move or update an object
163 // depeneding on the setting of 'selected', 'physical, ...
164 // This flag is the true test -- if true, the object is being acted on in the physical world
165 public abstract bool IsPhysicallyActive { get; }
166
167 // Detailed state of the object.
109 public abstract bool IsSolid { get; } 168 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 169 public abstract bool IsStatic { get; }
170 public abstract bool IsSelected { get; }
171
172 // Materialness
173 public MaterialAttributes.Material Material { get; private set; }
174 public override void SetMaterial(int material)
175 {
176 Material = (MaterialAttributes.Material)material;
177
178 // Setting the material sets the material attributes also.
179 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
180 Friction = matAttrib.friction;
181 Restitution = matAttrib.restitution;
182 Density = matAttrib.density / BSParam.DensityScaleFactor;
183 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
184 }
111 185
112 // Stop all physical motion. 186 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 187 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 188 public abstract void ZeroAngularMotion(bool inTaintTime);
115 189
116 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
117 public virtual void StepVehicle(float timeStep) { }
118
119 // Update the physical location and motion of the object. Called with data from Bullet. 190 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 191 public abstract void UpdateProperties(EntityProperties entprop);
121 192
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 193 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 194 public abstract OMV.Vector3 ForcePosition { get; set; }
127 195
128 public abstract OMV.Quaternion RawOrientation { get; set; } 196 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 197 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 198
199 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 200 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 201
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 202 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +205,32 @@ public abstract class BSPhysObject : PhysicsActor
136 205
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 206 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 207
208 // The current velocity forward
209 public virtual float ForwardSpeed
210 {
211 get
212 {
213 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
214 return characterOrientedVelocity.X;
215 }
216 }
217 // The forward speed we are trying to achieve (TargetVelocity)
218 public virtual float TargetVelocitySpeed
219 {
220 get
221 {
222 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
223 return characterOrientedVelocity.X;
224 }
225 }
226
227 // The user can optionally set the center of mass. The user's setting will override any
228 // computed center-of-mass (like in linksets).
229 public OMV.Vector3? UserSetCenterOfMass { get; set; }
230
231 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
232 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
233
139 #region Collisions 234 #region Collisions
140 235
141 // Requested number of milliseconds between collision events. Zero means disabled. 236 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,38 +241,82 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 241 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 242 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 243 protected long CollidingGroundStep { get; set; }
244 // The simulation step that last collided with an object
245 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 246 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 247 protected CollisionFlags CurrentCollisionFlags { get; set; }
248 // On a collision, check the collider and remember if the last collider was moving
249 // Used to modify the standing of avatars (avatars on stationary things stand still)
250 protected bool ColliderIsMoving;
251
252 // Count of collisions for this object
253 protected long CollisionAccumulation { get; set; }
254
255 public override bool IsColliding {
256 get { return (CollidingStep == PhysicsScene.SimulationStep); }
257 set {
258 if (value)
259 CollidingStep = PhysicsScene.SimulationStep;
260 else
261 CollidingStep = 0;
262 }
263 }
264 public override bool CollidingGround {
265 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
266 set
267 {
268 if (value)
269 CollidingGroundStep = PhysicsScene.SimulationStep;
270 else
271 CollidingGroundStep = 0;
272 }
273 }
274 public override bool CollidingObj {
275 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
276 set {
277 if (value)
278 CollidingObjectStep = PhysicsScene.SimulationStep;
279 else
280 CollidingObjectStep = 0;
281 }
282 }
151 283
152 // The collisions that have been collected this tick 284 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 285 protected CollisionEventUpdate CollisionCollection;
286 // Remember collisions from last tick for fancy collision based actions
287 // (like a BSCharacter walking up stairs).
288 protected CollisionEventUpdate CollisionsLastTick;
154 289
155 // The simulation step is telling this object about a collision. 290 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 291 // Return 'true' if a collision was processed and should be sent up.
292 // 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 293 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 294 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 295 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 296 {
161 bool ret = false; 297 bool ret = false;
162 298
163 // The following lines make IsColliding() and IsCollidingGround() work 299 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 300 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 301 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 302 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 303 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 304 }
169 305 else
170 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
172 { 306 {
173 return ret; 307 CollidingObjectStep = PhysicsScene.SimulationStep;
174 } 308 }
175 309
176 // if someone has subscribed for collision events.... 310 CollisionAccumulation++;
311
312 // For movement tests, remember if we are colliding with an object that is moving.
313 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
314
315 // If someone has subscribed for collision events log the collision so it will be reported up
177 if (SubscribedEvents()) { 316 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 317 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 318 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
180 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 319 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
181 320
182 ret = true; 321 ret = true;
183 } 322 }
@@ -191,8 +330,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 330 public virtual bool SendCollisions()
192 { 331 {
193 bool ret = true; 332 bool ret = true;
333
194 // If the 'no collision' call, force it to happen right now so quick collision_end 334 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 335 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 336
197 // throttle the collisions to the number of milliseconds specified in the subscription 337 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 338 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +347,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 347 ret = false;
208 } 348 }
209 349
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 350 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 351 base.SendCollisionUpdate(CollisionCollection);
212 352
213 // The collisionCollection structure is passed around in the simulator. 353 // Remember the collisions from this tick for some collision specific processing.
354 CollisionsLastTick = CollisionCollection;
355
356 // 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. 357 // Make sure we don't have a handle to that one and that a new one is used for next time.
358 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
359 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 360 CollisionCollection = new CollisionEventUpdate();
216 } 361 }
217 return ret; 362 return ret;
@@ -229,7 +374,8 @@ public abstract class BSPhysObject : PhysicsActor
229 374
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 375 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 376 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 377 if (PhysBody.HasPhysicalBody)
378 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 379 });
234 } 380 }
235 else 381 else
@@ -243,21 +389,187 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 389 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 390 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 391 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 392 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
393 if (PhysBody.HasPhysicalBody)
394 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 395 });
248 } 396 }
249 // Return 'true' if the simulator wants collision events 397 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() { 398 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0); 399 return (SubscribedEventsMs > 0);
252 } 400 }
401 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
402 // each time called. So this is built to be light weight for each collision and to do
403 // all the processing when the user asks for the info.
404 public void ComputeCollisionScore()
405 {
406 // Scale the collision count by the time since the last collision.
407 // The "+1" prevents dividing by zero.
408 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1;
409 CollisionScore = CollisionAccumulation / timeAgo;
410 }
411 public override float CollisionScore { get; set; }
253 412
254 #endregion // Collisions 413 #endregion // Collisions
255 414
415 #region Per Simulation Step actions
416 // There are some actions that must be performed for a physical object before each simulation step.
417 // These actions are optional so, rather than scanning all the physical objects and asking them
418 // if they have anything to do, a physical object registers for an event call before the step is performed.
419 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
420 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
421 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
422 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
423 {
424 string identifier = op + "-" + id.ToString();
425
426 lock (RegisteredPrestepActions)
427 {
428 // Clean out any existing action
429 UnRegisterPreStepAction(op, id);
430 RegisteredPrestepActions[identifier] = actn;
431 PhysicsScene.BeforeStep += actn;
432 }
433 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
434 }
435
436 // Unregister a pre step action. Safe to call if the action has not been registered.
437 // Returns 'true' if an action was actually removed
438 protected bool UnRegisterPreStepAction(string op, uint id)
439 {
440 string identifier = op + "-" + id.ToString();
441 bool removed = false;
442 lock (RegisteredPrestepActions)
443 {
444 if (RegisteredPrestepActions.ContainsKey(identifier))
445 {
446 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
447 RegisteredPrestepActions.Remove(identifier);
448 removed = true;
449 }
450 }
451 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
452 return removed;
453 }
454
455 protected void UnRegisterAllPreStepActions()
456 {
457 lock (RegisteredPrestepActions)
458 {
459 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
460 {
461 PhysicsScene.BeforeStep -= kvp.Value;
462 }
463 RegisteredPrestepActions.Clear();
464 }
465 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
466 }
467
468 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
469 {
470 string identifier = op + "-" + id.ToString();
471
472 lock (RegisteredPoststepActions)
473 {
474 // Clean out any existing action
475 UnRegisterPostStepAction(op, id);
476 RegisteredPoststepActions[identifier] = actn;
477 PhysicsScene.AfterStep += actn;
478 }
479 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
480 }
481
482 // Unregister a pre step action. Safe to call if the action has not been registered.
483 // Returns 'true' if an action was actually removed.
484 protected bool UnRegisterPostStepAction(string op, uint id)
485 {
486 string identifier = op + "-" + id.ToString();
487 bool removed = false;
488 lock (RegisteredPoststepActions)
489 {
490 if (RegisteredPoststepActions.ContainsKey(identifier))
491 {
492 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
493 RegisteredPoststepActions.Remove(identifier);
494 removed = true;
495 }
496 }
497 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
498 return removed;
499 }
500
501 protected void UnRegisterAllPostStepActions()
502 {
503 lock (RegisteredPoststepActions)
504 {
505 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
506 {
507 PhysicsScene.AfterStep -= kvp.Value;
508 }
509 RegisteredPoststepActions.Clear();
510 }
511 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
512 }
513
514 // When an update to the physical properties happens, this event is fired to let
515 // different actors to modify the update before it is passed around
516 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
517 public event PreUpdatePropertyAction OnPreUpdateProperty;
518 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
519 {
520 PreUpdatePropertyAction actions = OnPreUpdateProperty;
521 if (actions != null)
522 actions(ref entprop);
523 }
524
525 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
526 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
527 {
528 lock (RegisteredPreUpdatePropertyActions)
529 {
530 // Clean out any existing action
531 UnRegisterPreUpdatePropertyAction(identifier);
532 RegisteredPreUpdatePropertyActions[identifier] = actn;
533 OnPreUpdateProperty += actn;
534 }
535 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
536 }
537 public bool UnRegisterPreUpdatePropertyAction(string identifier)
538 {
539 bool removed = false;
540 lock (RegisteredPreUpdatePropertyActions)
541 {
542 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
543 {
544 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
545 RegisteredPreUpdatePropertyActions.Remove(identifier);
546 removed = true;
547 }
548 }
549 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
550 return removed;
551 }
552 public void UnRegisterAllPreUpdatePropertyActions()
553 {
554 lock (RegisteredPreUpdatePropertyActions)
555 {
556 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
557 {
558 OnPreUpdateProperty -= kvp.Value;
559 }
560 RegisteredPreUpdatePropertyActions.Clear();
561 }
562 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
563 }
564
565 #endregion // Per Simulation Step actions
566
256 // High performance detailed logging routine used by the physical objects. 567 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 568 protected void DetailLog(string msg, params Object[] args)
258 { 569 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 570 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 571 PhysicsScene.DetailLog(msg, args);
261 } 572 }
573
262} 574}
263} 575}
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..6a5461a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -39,51 +39,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin
39{ 39{
40 40
41 [Serializable] 41 [Serializable]
42public sealed class BSPrim : BSPhysObject 42public class BSPrim : BSPhysObject
43{ 43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 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;
57 private OMV.Vector3 _force; 58 private OMV.Vector3 _force;
58 private OMV.Vector3 _velocity; 59 private OMV.Vector3 _velocity;
59 private OMV.Vector3 _torque; 60 private OMV.Vector3 _torque;
60 private float _collisionScore;
61 private OMV.Vector3 _acceleration; 61 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation; 62 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 63 private int _physicsActorType;
64 private bool _isPhysical; 64 private bool _isPhysical;
65 private bool _flying; 65 private bool _flying;
66 private float _friction;
67 private float _restitution;
68 private bool _setAlwaysRun; 66 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 67 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 68 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 69 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 70 private bool _kinematic;
76 private float _buoyancy; 71 private float _buoyancy;
77 72
78 private BSDynamics _vehicle; 73 private int CrossingFailures { get; set; }
79 74
75 public BSDynamics VehicleController { get; private set; }
76
77 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 78 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 79 private float _PIDTau;
83 private bool _useHoverPID; 80
81 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 82 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 83 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 84 private float _PIDHoverTau;
87 85
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,31 +91,29 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 91 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 92 _position = pos;
95 _size = size; 93 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 95 _orientation = rotation;
98 _buoyancy = 1f; 96 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 97 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 98 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 99 BaseShape = pbs;
102 _isPhysical = pisPhysical; 100 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 101 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
106 _restitution = PhysicsScene.Params.defaultRestitution;
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
108 _mass = CalculateMass();
109 102
110 // No body or shape yet 103 VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 104
112 PhysShape = new BulletShape(IntPtr.Zero); 105 _mass = CalculateMass();
113 106
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 107 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 108 // do the actual object creation at taint time
116 PhysicsScene.TaintedObject("BSPrim.create", delegate() 109 PhysicsScene.TaintedObject("BSPrim.create", delegate()
117 { 110 {
111 // Make sure the object is being created with some sanity.
112 ExtremeSanityCheck(true /* inTaintTime */);
113
118 CreateGeomAndObject(true); 114 CreateGeomAndObject(true);
119 115
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 116 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 117 });
122 } 118 }
123 119
@@ -125,15 +121,7 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 121 public override void Destroy()
126 { 122 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 123 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
128 124 base.Destroy();
129 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot;
131 int childrenBefore = Linkset.NumberOfChildren;
132
133 Linkset = Linkset.RemoveMeFromLinkset(this);
134
135 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
136 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
137 125
138 // Undo any vehicle properties 126 // Undo any vehicle properties
139 this.VehicleType = (int)Vehicle.TYPE_NONE; 127 this.VehicleType = (int)Vehicle.TYPE_NONE;
@@ -142,8 +130,10 @@ public sealed class BSPrim : BSPhysObject
142 { 130 {
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 132 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 133 PhysicsScene.Shapes.DereferenceBody(PhysBody, null);
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 134 PhysBody.Clear();
135 PhysicsScene.Shapes.DereferenceShape(PhysShape, null);
136 PhysShape.Clear();
147 }); 137 });
148 } 138 }
149 139
@@ -157,31 +147,37 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 147 // 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. 148 // the physical shape, that is done when the geometry is built.
159 _size = value; 149 _size = value;
150 Scale = _size;
160 ForceBodyShapeRebuild(false); 151 ForceBodyShapeRebuild(false);
161 } 152 }
162 } 153 }
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 154
167 public override PrimitiveBaseShape Shape { 155 public override PrimitiveBaseShape Shape {
168 set { 156 set {
169 BaseShape = value; 157 BaseShape = value;
158 PrimAssetState = PrimAssetCondition.Unknown;
170 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
171 } 160 }
172 } 161 }
173 // Whatever the linkset wants is what I want. 162 // 'unknown' says to choose the best type
174 public override BSPhysicsShapeType PreferredPhysicalShape 163 public override BSPhysicsShapeType PreferredPhysicalShape
175 { get { return Linkset.PreferredPhysicalShape(this); } } 164 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
176 165
177 public override bool ForceBodyShapeRebuild(bool inTaintTime) 166 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 { 167 {
179 LastAssetBuildFailed = false; 168 if (inTaintTime)
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 { 169 {
182 _mass = CalculateMass(); // changing the shape changes the mass 170 _mass = CalculateMass(); // changing the shape changes the mass
183 CreateGeomAndObject(true); 171 CreateGeomAndObject(true);
184 }); 172 }
173 else
174 {
175 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
176 {
177 _mass = CalculateMass(); // changing the shape changes the mass
178 CreateGeomAndObject(true);
179 });
180 }
185 return true; 181 return true;
186 } 182 }
187 public override bool Grabbed { 183 public override bool Grabbed {
@@ -189,46 +185,44 @@ public sealed class BSPrim : BSPhysObject
189 } 185 }
190 } 186 }
191 public override bool Selected { 187 public override bool Selected {
192 set { 188 set
193 _isSelected = value; 189 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 190 if (value != _isSelected)
195 { 191 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 192 _isSelected = value;
197 SetObjectDynamic(false); 193 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 194 {
195 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
196 SetObjectDynamic(false);
197 });
198 }
199 } 199 }
200 } 200 }
201 public override void CrossingFailure() { return; } 201 public override bool IsSelected
202 {
203 get { return _isSelected; }
204 }
202 205
203 // link me to the specified parent 206 public override void CrossingFailure()
204 public override void link(PhysicsActor obj) { 207 {
205 BSPrim parent = obj as BSPrim; 208 CrossingFailures++;
206 if (parent != null) 209 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
207 { 210 {
208 BSPhysObject parentBefore = Linkset.LinksetRoot; 211 base.RaiseOutOfBounds(RawPosition);
209 int childrenBefore = Linkset.NumberOfChildren; 212 }
210 213 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
211 Linkset = parent.Linkset.AddMeToLinkset(this); 214 {
212 215 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
213 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
214 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
215 } 216 }
216 return; 217 return;
217 } 218 }
218 219
220 // link me to the specified parent
221 public override void link(PhysicsActor obj) {
222 }
223
219 // delink me from my linkset 224 // delink me from my linkset
220 public override void delink() { 225 public override void delink() {
221 // TODO: decide if this parent checking needs to happen at taint time
222 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
223
224 BSPhysObject parentBefore = Linkset.LinksetRoot;
225 int childrenBefore = Linkset.NumberOfChildren;
226
227 Linkset = Linkset.RemoveMeFromLinkset(this);
228
229 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
230 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
231 return;
232 } 226 }
233 227
234 // Set motion values to zero. 228 // Set motion values to zero.
@@ -244,7 +238,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 238 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 239 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 240 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 241 if (PhysBody.HasPhysicalBody)
242 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 243 });
249 } 244 }
250 public override void ZeroAngularMotion(bool inTaintTime) 245 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,16 +248,107 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 248 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 249 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 250 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 251 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 252 if (PhysBody.HasPhysicalBody)
253 {
254 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
255 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
256 }
258 }); 257 });
259 } 258 }
260 259
260 bool TryExperimentalLockAxisCode = false;
261 BSConstraint LockAxisConstraint = null;
261 public override void LockAngularMotion(OMV.Vector3 axis) 262 public override void LockAngularMotion(OMV.Vector3 axis)
262 { 263 {
263 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 264 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
265
266 // "1" means free, "0" means locked
267 OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f);
268 if (axis.X != 1) locking.X = 0f;
269 if (axis.Y != 1) locking.Y = 0f;
270 if (axis.Z != 1) locking.Z = 0f;
271 LockedAxis = locking;
272
273 if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree)
274 {
275 // Lock that axis by creating a 6DOF constraint that has one end in the world and
276 // the other in the object.
277 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
278 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
279
280 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
281 {
282 CleanUpLockAxisPhysicals(true /* inTaintTime */);
283
284 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody,
285 OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation),
286 true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
287 LockAxisConstraint = axisConstrainer;
288 PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
289
290 // The constraint is tied to the world and oriented to the prim.
291
292 // Free to move linearly
293 OMV.Vector3 linearLow = OMV.Vector3.Zero;
294 OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
295 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
296
297 // Angular with some axis locked
298 float f2PI = (float)Math.PI * 2f;
299 OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
300 OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
301 if (LockedAxis.X != 1f)
302 {
303 angularLow.X = 0f;
304 angularHigh.X = 0f;
305 }
306 if (LockedAxis.Y != 1f)
307 {
308 angularLow.Y = 0f;
309 angularHigh.Y = 0f;
310 }
311 if (LockedAxis.Z != 1f)
312 {
313 angularLow.Z = 0f;
314 angularHigh.Z = 0f;
315 }
316 axisConstrainer.SetAngularLimits(angularLow, angularHigh);
317
318 DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
319 LocalID, linearLow, linearHigh, angularLow, angularHigh);
320
321 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
322 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
323
324 axisConstrainer.RecomputeConstraintVariables(RawMass);
325 });
326 }
327 else
328 {
329 // Everything seems unlocked
330 CleanUpLockAxisPhysicals(false /* inTaintTime */);
331 }
332
264 return; 333 return;
265 } 334 }
335 // Get rid of any constraint built for LockAxis
336 // Most often the constraint is removed when the constraint collection is cleaned for this prim.
337 private void CleanUpLockAxisPhysicals(bool inTaintTime)
338 {
339 if (LockAxisConstraint != null)
340 {
341 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate()
342 {
343 if (LockAxisConstraint != null)
344 {
345 PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
346 LockAxisConstraint = null;
347 DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID);
348 }
349 });
350 }
351 }
266 352
267 public override OMV.Vector3 RawPosition 353 public override OMV.Vector3 RawPosition
268 { 354 {
@@ -271,41 +357,41 @@ public sealed class BSPrim : BSPhysObject
271 } 357 }
272 public override OMV.Vector3 Position { 358 public override OMV.Vector3 Position {
273 get { 359 get {
274 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this);
277
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 360 // 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); 361 // _position = ForcePosition;
280 return _position; 362 return _position;
281 } 363 }
282 set { 364 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 365 // If the position must be forced into the physics engine, use ForcePosition.
366 // All positions are given in world positions.
284 if (_position == value) 367 if (_position == value)
285 { 368 {
369 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 370 return;
287 } 371 }
288 _position = value; 372 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 373 PositionSanityCheck(false);
374
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 375 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 376 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 377 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 378 ForcePosition = _position;
295 ActivateIfPhysical(false);
296 }); 379 });
297 } 380 }
298 } 381 }
382
299 public override OMV.Vector3 ForcePosition { 383 public override OMV.Vector3 ForcePosition {
300 get { 384 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 385 _position = PhysicsScene.PE.GetPosition(PhysBody);
302 return _position; 386 return _position;
303 } 387 }
304 set { 388 set {
305 _position = value; 389 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 390 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 391 {
308 ActivateIfPhysical(false); 392 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
393 ActivateIfPhysical(false);
394 }
309 } 395 }
310 } 396 }
311 397
@@ -316,119 +402,231 @@ public sealed class BSPrim : BSPhysObject
316 { 402 {
317 bool ret = false; 403 bool ret = false;
318 404
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 405 // We don't care where non-physical items are placed
406 if (!IsPhysicallyActive)
407 return ret;
408
409 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
410 {
411 // The physical object is out of the known/simulated area.
412 // Upper levels of code will handle the transition to other areas so, for
413 // the time, we just ignore the position.
414 return ret;
415 }
416
417 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 418 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 419 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
420 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
322 { 421 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 422 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 423 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 424 // If the object is below ground it just has to be moved up because pushing will
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 425 // not get it through the terrain
426 _position.Z = targetHeight;
427 if (inTaintTime)
428 {
429 ForcePosition = _position;
430 }
431 // If we are throwing the object around, zero its other forces
432 ZeroMotion(inTaintTime);
327 ret = true; 433 ret = true;
328 } 434 }
329 435
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 436 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 437 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 438 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 439 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 440 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 441 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 442 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 443 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
444
445 // Apply upforce and overcome gravity.
446 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
447 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
448 AddForce(correctionForce, false, inTaintTime);
338 ret = true; 449 ret = true;
339 } 450 }
340 } 451 }
341 452
342 // TODO: check for out of bounds 453 return ret;
454 }
455
456 // Occasionally things will fly off and really get lost.
457 // Find the wanderers and bring them back.
458 // Return 'true' if some parameter need some sanity.
459 private bool ExtremeSanityCheck(bool inTaintTime)
460 {
461 bool ret = false;
343 462
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 463 uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
345 if (ret) 464 // There have been instances of objects getting thrown way out of bounds and crashing
465 // the border crossing code.
466 if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere
467 || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere
468 || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere)
346 { 469 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 470 _position = new OMV.Vector3(10, 10, 50);
348 { 471 ZeroMotion(inTaintTime);
349 // Apply upforce and overcome gravity. 472 ret = true;
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; 473 }
351 }); 474 if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity)
475 {
476 _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity);
477 ret = true;
352 } 478 }
479 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
480 {
481 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
482 ret = true;
483 }
484
353 return ret; 485 return ret;
354 } 486 }
355 487
356 // Return the effective mass of the object. 488 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 489 // The definition of this call is to return the mass of the prim.
490 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 491 public override float Mass
359 { 492 {
360 get 493 get { return _mass; }
361 { 494 }
362 return Linkset.LinksetMass; 495 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
363 // return _mass; 496 public virtual float TotalMass
364 } 497 {
498 get { return _mass; }
365 } 499 }
366
367 // used when we only want this prim's mass and not the linkset thing 500 // used when we only want this prim's mass and not the linkset thing
368 public override float RawMass { 501 public override float RawMass {
369 get { return _mass; } 502 get { return _mass; }
370 } 503 }
371 // Set the physical mass to the passed mass. 504 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 505 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 506 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 507 {
375 if (IsStatic) 508 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
376 { 509 {
377 Inertia = OMV.Vector3.Zero; 510 if (IsStatic)
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); 511 {
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 512 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
513 Inertia = OMV.Vector3.Zero;
514 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
515 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
516 }
517 else
518 {
519 if (inWorld)
520 {
521 // Changing interesting properties doesn't change proxy and collision cache
522 // information. The Bullet solution is to re-add the object to the world
523 // after parameters are changed.
524 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
525 }
526
527 // The computation of mass props requires gravity to be set on the object.
528 Gravity = ComputeGravity(Buoyancy);
529 PhysicsScene.PE.SetGravity(PhysBody, Gravity);
530
531 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
532 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
533 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
534
535 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
536 LocalID, physMass, Inertia, Gravity, inWorld);
537
538 if (inWorld)
539 {
540 AddObjectToPhysicalWorld();
541 }
542 }
380 } 543 }
381 else 544 }
545
546 // Return what gravity should be set to this very moment
547 public OMV.Vector3 ComputeGravity(float buoyancy)
548 {
549 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
550
551 if (!IsStatic)
382 { 552 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 553 ret *= (1f - buoyancy);
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 554 ret *= GravModifier;
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
386 // center of mass is at the zero of the object
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
389 } 555 }
556
557 return ret;
390 } 558 }
391 559
392 // Is this used? 560 // Is this used?
393 public override OMV.Vector3 CenterOfMass 561 public override OMV.Vector3 CenterOfMass
394 { 562 {
395 get { return Linkset.CenterOfMass; } 563 get { return RawPosition; }
396 } 564 }
397 565
398 // Is this used? 566 // Is this used?
399 public override OMV.Vector3 GeometricCenter 567 public override OMV.Vector3 GeometricCenter
400 { 568 {
401 get { return Linkset.GeometricCenter; } 569 get { return RawPosition; }
402 } 570 }
403 571
404 public override OMV.Vector3 Force { 572 public override OMV.Vector3 Force {
405 get { return _force; } 573 get { return _force; }
406 set { 574 set {
407 _force = value; 575 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 576 if (_force != OMV.Vector3.Zero)
409 { 577 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 578 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 579 // Bullet clears the forces applied last frame.
412 }); 580 RegisterPreStepAction("BSPrim.setForce", LocalID,
581 delegate(float timeStep)
582 {
583 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
584 {
585 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
586 return;
587 }
588
589 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
590 if (PhysBody.HasPhysicalBody)
591 {
592 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
593 ActivateIfPhysical(false);
594 }
595 }
596 );
597 }
598 else
599 {
600 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
601 }
413 } 602 }
414 } 603 }
415 604
416 public override int VehicleType { 605 public override int VehicleType {
417 get { 606 get {
418 return (int)_vehicle.Type; // if we are a vehicle, return that type 607 return (int)VehicleController.Type; // if we are a vehicle, return that type
419 } 608 }
420 set { 609 set {
421 Vehicle type = (Vehicle)value; 610 Vehicle type = (Vehicle)value;
422 611
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() 612 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 613 {
428 // Done at taint time so we're sure the physics engine is not using the variables 614 // 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. 615 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 616 VehicleController.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 617 ActivateIfPhysical(false);
618
619 // If an active vehicle, register the vehicle code to be called before each step
620 if (VehicleController.Type == Vehicle.TYPE_NONE)
621 {
622 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
623 UnRegisterPostStepAction("BSPrim.Vehicle", LocalID);
624 }
625 else
626 {
627 RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step);
628 RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep);
629 }
432 }); 630 });
433 } 631 }
434 } 632 }
@@ -436,7 +634,7 @@ public sealed class BSPrim : BSPhysObject
436 { 634 {
437 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 635 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
438 { 636 {
439 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 637 VehicleController.ProcessFloatVehicleParam((Vehicle)param, value);
440 ActivateIfPhysical(false); 638 ActivateIfPhysical(false);
441 }); 639 });
442 } 640 }
@@ -444,7 +642,7 @@ public sealed class BSPrim : BSPhysObject
444 { 642 {
445 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 643 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
446 { 644 {
447 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 645 VehicleController.ProcessVectorVehicleParam((Vehicle)param, value);
448 ActivateIfPhysical(false); 646 ActivateIfPhysical(false);
449 }); 647 });
450 } 648 }
@@ -452,7 +650,7 @@ public sealed class BSPrim : BSPhysObject
452 { 650 {
453 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 651 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
454 { 652 {
455 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 653 VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation);
456 ActivateIfPhysical(false); 654 ActivateIfPhysical(false);
457 }); 655 });
458 } 656 }
@@ -460,27 +658,10 @@ public sealed class BSPrim : BSPhysObject
460 { 658 {
461 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 659 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
462 { 660 {
463 _vehicle.ProcessVehicleFlags(param, remove); 661 VehicleController.ProcessVehicleFlags(param, remove);
464 }); 662 });
465 } 663 }
466 664
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 665 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 666 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 667 bool newValue = (param != 0);
@@ -495,6 +676,81 @@ public sealed class BSPrim : BSPhysObject
495 } 676 }
496 return; 677 return;
497 } 678 }
679 public override void SetMaterial(int material)
680 {
681 base.SetMaterial(material);
682 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate()
683 {
684 UpdatePhysicalParameters();
685 });
686 }
687 public override float Friction
688 {
689 get { return base.Friction; }
690 set
691 {
692 if (base.Friction != value)
693 {
694 base.Friction = value;
695 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate()
696 {
697 UpdatePhysicalParameters();
698 });
699 }
700 }
701 }
702 public override float Restitution
703 {
704 get { return base.Restitution; }
705 set
706 {
707 if (base.Restitution != value)
708 {
709 base.Restitution = value;
710 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate()
711 {
712 UpdatePhysicalParameters();
713 });
714 }
715 }
716 }
717 // The simulator/viewer keep density as 100kg/m3.
718 // Remember to use BSParam.DensityScaleFactor to create the physical density.
719 public override float Density
720 {
721 get { return base.Density; }
722 set
723 {
724 if (base.Density != value)
725 {
726 base.Density = value;
727 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate()
728 {
729 UpdatePhysicalParameters();
730 });
731 }
732 }
733 }
734 public override float GravModifier
735 {
736 get { return base.GravModifier; }
737 set
738 {
739 if (base.GravModifier != value)
740 {
741 base.GravModifier = value;
742 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate()
743 {
744 UpdatePhysicalParameters();
745 });
746 }
747 }
748 }
749 public override OMV.Vector3 RawVelocity
750 {
751 get { return _velocity; }
752 set { _velocity = value; }
753 }
498 public override OMV.Vector3 Velocity { 754 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 755 get { return _velocity; }
500 set { 756 set {
@@ -502,30 +758,53 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 758 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 759 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 760 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 761 ForceVelocity = _velocity;
506 }); 762 });
507 } 763 }
508 } 764 }
509 public override OMV.Vector3 ForceVelocity { 765 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 766 get { return _velocity; }
511 set { 767 set {
512 _velocity = value; 768 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 769
770 _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
771 if (PhysBody.HasPhysicalBody)
772 {
773 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
774 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
775 ActivateIfPhysical(false);
776 }
514 } 777 }
515 } 778 }
516 public override OMV.Vector3 Torque { 779 public override OMV.Vector3 Torque {
517 get { return _torque; } 780 get { return _torque; }
518 set { 781 set {
519 _torque = value; 782 _torque = value;
520 AddAngularForce(_torque, false, false); 783 if (_torque != OMV.Vector3.Zero)
784 {
785 // If the torque is non-zero, it must be reapplied each tick because
786 // Bullet clears the forces applied last frame.
787 RegisterPreStepAction("BSPrim.setTorque", LocalID,
788 delegate(float timeStep)
789 {
790 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
791 {
792 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
793 return;
794 }
795
796 if (PhysBody.HasPhysicalBody)
797 AddAngularForce(_torque, false, true);
798 }
799 );
800 }
801 else
802 {
803 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
804 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 805 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 806 }
523 } 807 }
524 public override float CollisionScore {
525 get { return _collisionScore; }
526 set { _collisionScore = value;
527 }
528 }
529 public override OMV.Vector3 Acceleration { 808 public override OMV.Vector3 Acceleration {
530 get { return _acceleration; } 809 get { return _acceleration; }
531 set { _acceleration = value; } 810 set { _acceleration = value; }
@@ -537,23 +816,16 @@ public sealed class BSPrim : BSPhysObject
537 } 816 }
538 public override OMV.Quaternion Orientation { 817 public override OMV.Quaternion Orientation {
539 get { 818 get {
540 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this))
542 {
543 _orientation = Linkset.Orientation(this);
544 }
545 return _orientation; 819 return _orientation;
546 } 820 }
547 set { 821 set {
548 if (_orientation == value) 822 if (_orientation == value)
549 return; 823 return;
550 _orientation = value; 824 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 825
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 826 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 827 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 828 ForceOrientation = _orientation;
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
557 }); 829 });
558 } 830 }
559 } 831 }
@@ -562,13 +834,14 @@ public sealed class BSPrim : BSPhysObject
562 { 834 {
563 get 835 get
564 { 836 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 837 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 838 return _orientation;
567 } 839 }
568 set 840 set
569 { 841 {
570 _orientation = value; 842 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 843 if (PhysBody.HasPhysicalBody)
844 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
572 } 845 }
573 } 846 }
574 public override int PhysicsActorType { 847 public override int PhysicsActorType {
@@ -583,10 +856,11 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 856 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 857 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 858 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 859 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 860 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 861 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 862 ZeroMotion(true);
863
590 }); 864 });
591 } 865 }
592 } 866 }
@@ -604,6 +878,12 @@ public sealed class BSPrim : BSPhysObject
604 get { return !IsPhantom && !_isVolumeDetect; } 878 get { return !IsPhantom && !_isVolumeDetect; }
605 } 879 }
606 880
881 // The object is moving and is actively being dynamic in the physical world
882 public override bool IsPhysicallyActive
883 {
884 get { return !_isSelected && IsPhysical; }
885 }
886
607 // Make gravity work if the object is physical and not selected 887 // Make gravity work if the object is physical and not selected
608 // Called at taint-time!! 888 // Called at taint-time!!
609 private void SetObjectDynamic(bool forceRebuild) 889 private void SetObjectDynamic(bool forceRebuild)
@@ -618,19 +898,24 @@ public sealed class BSPrim : BSPhysObject
618 // isSolid: other objects bounce off of this object 898 // isSolid: other objects bounce off of this object
619 // isVolumeDetect: other objects pass through but can generate collisions 899 // isVolumeDetect: other objects pass through but can generate collisions
620 // collisionEvents: whether this object returns collision events 900 // collisionEvents: whether this object returns collision events
621 private void UpdatePhysicalParameters() 901 public virtual void UpdatePhysicalParameters()
622 { 902 {
623 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); 903 if (!PhysBody.HasPhysicalBody)
904 {
905 // This would only happen if updates are called for during initialization when the body is not set up yet.
906 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
907 return;
908 }
624 909
625 // Mangling all the physical properties requires the object not be in the physical world. 910 // 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). 911 // 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); 912 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 913
629 // Set up the object physicalness (does gravity and collisions move this object) 914 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 915 MakeDynamic(IsStatic);
631 916
632 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 917 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
633 _vehicle.Refresh(); 918 VehicleController.Refresh();
634 919
635 // Arrange for collision events if the simulator wants them 920 // Arrange for collision events if the simulator wants them
636 EnableCollisions(SubscribedEvents()); 921 EnableCollisions(SubscribedEvents());
@@ -638,25 +923,13 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 923 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 924 MakeSolid(IsSolid);
640 925
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 926 AddObjectToPhysicalWorld();
642 927
643 // Rebuild its shape 928 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 929 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
652 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that
654 // had been automatically disabled when the mass was set to zero.
655 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this);
657 930
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 931 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); 932 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 933 }
661 934
662 // "Making dynamic" means changing to and from static. 935 // "Making dynamic" means changing to and from static.
@@ -664,79 +937,78 @@ public sealed class BSPrim : BSPhysObject
664 // When dynamic, the object can fall and be pushed by others. 937 // When dynamic, the object can fall and be pushed by others.
665 // This is independent of its 'solidness' which controls what passes through 938 // This is independent of its 'solidness' which controls what passes through
666 // this object and what interacts with it. 939 // this object and what interacts with it.
667 private void MakeDynamic(bool makeStatic) 940 protected virtual void MakeDynamic(bool makeStatic)
668 { 941 {
669 if (makeStatic) 942 if (makeStatic)
670 { 943 {
671 // Become a Bullet 'static' object type 944 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 945 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 946 // Stop all movement
674 ZeroMotion(true); 947 ZeroMotion(true);
675 // Center of mass is at the center of the object 948
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 949 // Set various physical properties so other object interact properly
950 PhysicsScene.PE.SetFriction(PhysBody, Friction);
951 PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
952 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
953
677 // Mass is zero which disables a bunch of physics stuff in Bullet 954 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 955 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 956 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 957 if (BSParam.CcdMotionThreshold > 0f)
681 { 958 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 959 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 960 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 961 }
685 // There can be special things needed for implementing linksets 962
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 963 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 964 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 965 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 966 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
691 967
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 968 // This collides like a static object
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 969 PhysBody.collisionType = CollisionType.Static;
694 } 970 }
695 else 971 else
696 { 972 {
697 // Not a Bullet static object 973 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 974 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 975
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 976 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 977 PhysicsScene.PE.SetFriction(PhysBody, Friction);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 978 PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
979 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
703 980
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 981 // 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 982 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 983 // PhysicsScene.PE.ClearAllForces(BSBody);
707 984
708 // For good measure, make sure the transform is set through to the motion state 985 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 986 ForcePosition = _position;
710 987 ForceVelocity = _velocity;
711 // Center of mass is at the center of the object 988 ForceRotationalVelocity = _rotationalVelocity;
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
713 989
714 // A dynamic object has mass 990 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 991 UpdatePhysicalMassProperties(RawMass, false);
716 992
717 // Set collision detection parameters 993 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 994 if (BSParam.CcdMotionThreshold > 0f)
719 { 995 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 996 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 997 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 998 }
723 999
724 // Various values for simulation limits 1000 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 1001 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 1002 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 1003 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 1004 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 1005
730 // There might be special things needed for implementing linksets. 1006 // This collides like an object.
731 Linkset.MakeDynamic(this); 1007 PhysBody.collisionType = CollisionType.Dynamic;
732 1008
733 // Force activation of the object so Bullet will act on it. 1009 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 1010 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 1011 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
740 } 1012 }
741 } 1013 }
742 1014
@@ -746,7 +1018,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 1018 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 1019 private void MakeSolid(bool makeSolid)
748 { 1020 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 1021 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 1022 if (makeSolid)
751 { 1023 {
752 // Verify the previous code created the correct shape for this type of thing. 1024 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +1026,7 @@ public sealed class BSPrim : BSPhysObject
754 { 1026 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 1027 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 1028 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 1029 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 1030 }
759 else 1031 else
760 { 1032 {
@@ -762,9 +1034,10 @@ public sealed class BSPrim : BSPhysObject
762 { 1034 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 1035 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 1036 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 1037 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 1038
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 1039 // Change collision info from a static object to a ghosty collision object
1040 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 1041 }
769 } 1042 }
770 1043
@@ -773,8 +1046,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 1046 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 1047 private void ActivateIfPhysical(bool forceIt)
775 { 1048 {
776 if (IsPhysical) 1049 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 1050 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 1051 }
779 1052
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 1053 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +1055,27 @@ public sealed class BSPrim : BSPhysObject
782 { 1055 {
783 if (wantsCollisionEvents) 1056 if (wantsCollisionEvents)
784 { 1057 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 1058 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1059 }
1060 else
1061 {
1062 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1063 }
1064 }
1065
1066 // Add me to the physical world.
1067 // Object MUST NOT already be in the world.
1068 // This routine exists because some assorted properties get mangled by adding to the world.
1069 internal void AddObjectToPhysicalWorld()
1070 {
1071 if (PhysBody.HasPhysicalBody)
1072 {
1073 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
786 } 1074 }
787 else 1075 else
788 { 1076 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 1077 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1078 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 1079 }
791 } 1080 }
792 1081
@@ -805,18 +1094,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 1094 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 1095 set { _throttleUpdates = value; }
807 } 1096 }
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 { 1097 public bool IsPhantom {
821 get { 1098 get {
822 // SceneObjectPart removes phantom objects from the physics scene 1099 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,32 +1108,23 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 1108 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 1109 {
833 if (_floatOnWater) 1110 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 1111 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 1112 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 1113 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 1114 });
838 } 1115 }
839 } 1116 }
840 public override OMV.Vector3 RotationalVelocity { 1117 public override OMV.Vector3 RotationalVelocity {
841 get { 1118 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; 1119 return _rotationalVelocity;
852 } 1120 }
853 set { 1121 set {
854 _rotationalVelocity = value; 1122 _rotationalVelocity = value;
1123 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 1124 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 1125 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 1126 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 1127 ForceRotationalVelocity = _rotationalVelocity;
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
860 }); 1128 });
861 } 1129 }
862 } 1130 }
@@ -865,8 +1133,14 @@ public sealed class BSPrim : BSPhysObject
865 return _rotationalVelocity; 1133 return _rotationalVelocity;
866 } 1134 }
867 set { 1135 set {
868 _rotationalVelocity = value; 1136 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 1137 if (PhysBody.HasPhysicalBody)
1138 {
1139 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1140 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1141 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1142 ActivateIfPhysical(false);
1143 }
870 } 1144 }
871 } 1145 }
872 public override bool Kinematic { 1146 public override bool Kinematic {
@@ -890,27 +1164,130 @@ public sealed class BSPrim : BSPhysObject
890 set { 1164 set {
891 _buoyancy = value; 1165 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1166 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 1167 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 1168 UpdatePhysicalMassProperties(RawMass, true);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 1169 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1170 ActivateIfPhysical(false);
896 } 1171 }
897 } 1172 }
898 1173
899 // Used for MoveTo 1174 // Used for MoveTo
900 public override OMV.Vector3 PIDTarget { 1175 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1176 set
902 } 1177 {
903 public override bool PIDActive { 1178 // TODO: add a sanity check -- don't move more than a region or something like that.
904 set { _usePID = value; } 1179 _PIDTarget = value;
1180 }
905 } 1181 }
906 public override float PIDTau { 1182 public override float PIDTau {
907 set { _PIDTau = value; } 1183 set { _PIDTau = value; }
908 } 1184 }
1185 public override bool PIDActive {
1186 set {
1187 if (value)
1188 {
1189 // We're taking over after this.
1190 ZeroMotion(true);
1191
1192 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1193 _PIDTau, // timeScale
1194 BSMotor.Infinite, // decay time scale
1195 BSMotor.InfiniteVector, // friction timescale
1196 1f // efficiency
1197 );
1198 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1199 _targetMotor.SetTarget(_PIDTarget);
1200 _targetMotor.SetCurrent(RawPosition);
1201 /*
1202 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1203 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1204
1205 _targetMotor.SetTarget(_PIDTarget);
1206 _targetMotor.SetCurrent(RawPosition);
1207 _targetMotor.TimeScale = _PIDTau;
1208 _targetMotor.Efficiency = 1f;
1209 */
1210
1211 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1212 {
1213 if (!IsPhysicallyActive)
1214 {
1215 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1216 return;
1217 }
1218
1219 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1220
1221 // 'movePosition' is where we'd like the prim to be at this moment.
1222 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1223
1224 // If we are very close to our target, turn off the movement motor.
1225 if (_targetMotor.ErrorIsZero())
1226 {
1227 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1228 LocalID, movePosition, RawPosition, Mass);
1229 ForcePosition = _targetMotor.TargetValue;
1230 _targetMotor.Enabled = false;
1231 }
1232 else
1233 {
1234 _position = movePosition;
1235 PositionSanityCheck(true /* intaintTime */);
1236 ForcePosition = _position;
1237 }
1238 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1239 });
1240 }
1241 else
1242 {
1243 // Stop any targetting
1244 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1245 }
1246 }
1247 }
909 1248
910 // Used for llSetHoverHeight and maybe vehicle height 1249 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1250 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1251 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1252 set {
1253 if (value)
1254 {
1255 // Turning the target on
1256 _hoverMotor = new BSFMotor("BSPrim.Hover",
1257 _PIDHoverTau, // timeScale
1258 BSMotor.Infinite, // decay time scale
1259 BSMotor.Infinite, // friction timescale
1260 1f // efficiency
1261 );
1262 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1263 _hoverMotor.SetCurrent(RawPosition.Z);
1264 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1265
1266 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1267 {
1268 // Don't do hovering while the object is selected.
1269 if (!IsPhysicallyActive)
1270 return;
1271
1272 _hoverMotor.SetCurrent(RawPosition.Z);
1273 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1274 float targetHeight = _hoverMotor.Step(timeStep);
1275
1276 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1277 // Compute the amount of force to push us there.
1278 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1279 // Undo anything the object thinks it's doing at the moment
1280 moveForce = -RawVelocity.Z * Mass;
1281
1282 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1283 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1284 });
1285 }
1286 else
1287 {
1288 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1289 }
1290 }
914 } 1291 }
915 public override float PIDHoverHeight { 1292 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1293 set { _PIDHoverHeight = value; }
@@ -919,8 +1296,35 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1296 set { _PIDHoverType = value; }
920 } 1297 }
921 public override float PIDHoverTau { 1298 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1299 set { _PIDHoverTau = value; }
923 } 1300 }
1301 // Based on current position, determine what we should be hovering at now.
1302 // Must recompute often. What if we walked offa cliff>
1303 private float ComputeCurrentPIDHoverHeight()
1304 {
1305 float ret = _PIDHoverHeight;
1306 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1307
1308 switch (_PIDHoverType)
1309 {
1310 case PIDHoverType.Ground:
1311 ret = groundHeight + _PIDHoverHeight;
1312 break;
1313 case PIDHoverType.GroundAndWater:
1314 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1315 if (groundHeight > waterHeight)
1316 {
1317 ret = groundHeight + _PIDHoverHeight;
1318 }
1319 else
1320 {
1321 ret = waterHeight + _PIDHoverHeight;
1322 }
1323 break;
1324 }
1325 return ret;
1326 }
1327
924 1328
925 // For RotLookAt 1329 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1330 public override OMV.Quaternion APIDTarget { set { return; } }
@@ -928,54 +1332,73 @@ public sealed class BSPrim : BSPhysObject
928 public override float APIDStrength { set { return; } } 1332 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1333 public override float APIDDamping { set { return; } }
930 1334
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1335 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1336 // Per documentation, max force is limited.
1337 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1338
1339 // Since this force is being applied in only one step, make this a force per second.
1340 addForce /= PhysicsScene.LastTimeStep;
1341 AddForce(addForce, pushforce, false /* inTaintTime */);
934 } 1342 }
1343
935 // Applying a force just adds this to the total force on the object. 1344 // Applying a force just adds this to the total force on the object.
1345 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1346 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1347 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1348 if (IsPhysicallyActive)
939 {
940 // _force += force;
941 lock (m_accumulatedForces)
942 m_accumulatedForces.Add(new OMV.Vector3(force));
943 }
944 else
945 { 1349 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1350 if (force.IsFinite())
947 return;
948 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero;
952 lock (m_accumulatedForces)
953 { 1351 {
954 // Sum the accumulated additional forces for one big force to apply once. 1352 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
955 foreach (OMV.Vector3 v in m_accumulatedForces) 1353
1354 OMV.Vector3 addForce = force;
1355 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
956 { 1356 {
957 fSum += v; 1357 // Bullet adds this central force to the total force for this tick
958 } 1358 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
959 m_accumulatedForces.Clear(); 1359 if (PhysBody.HasPhysicalBody)
1360 {
1361 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1362 ActivateIfPhysical(false);
1363 }
1364 });
960 } 1365 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 1366 else
962 if (fSum != OMV.Vector3.Zero) 1367 {
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 1368 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
964 }); 1369 return;
1370 }
1371 }
965 } 1372 }
966 1373
967 // An impulse force is scaled by the mass of the object. 1374 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 1375 // for an object, doesn't matter if force is a pushforce or not
969 { 1376 if (!IsPhysicallyActive)
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1377 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1378 if (impulse.IsFinite())
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1379 {
975 }); 1380 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1381 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1382
1383 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1384 {
1385 // Bullet adds this impulse immediately to the velocity
1386 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1387 if (PhysBody.HasPhysicalBody)
1388 {
1389 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1390 ActivateIfPhysical(false);
1391 }
1392 });
1393 }
1394 else
1395 {
1396 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1397 return;
1398 }
1399 }
976 } 1400 }
977 1401
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1402 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1403 AddAngularForce(force, pushforce, false);
981 } 1404 }
@@ -983,42 +1406,38 @@ public sealed class BSPrim : BSPhysObject
983 { 1406 {
984 if (force.IsFinite()) 1407 if (force.IsFinite())
985 { 1408 {
986 // _force += force; 1409 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1410 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1411 {
1412 if (PhysBody.HasPhysicalBody)
1413 {
1414 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1415 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1416 ActivateIfPhysical(false);
1417 }
1418 });
989 } 1419 }
990 else 1420 else
991 { 1421 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1422 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1423 return;
994 } 1424 }
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 } 1425 }
1426
1015 // A torque impulse. 1427 // A torque impulse.
1428 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1429 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1430 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1431 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1432 {
1018 OMV.Vector3 applyImpulse = impulse; 1433 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1434 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1435 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1436 if (PhysBody.HasPhysicalBody)
1437 {
1438 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1439 ActivateIfPhysical(false);
1440 }
1022 }); 1441 });
1023 } 1442 }
1024 1443
@@ -1301,23 +1720,10 @@ public sealed class BSPrim : BSPhysObject
1301 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; 1720 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1302 volume *= (profileEnd - profileBegin); 1721 volume *= (profileEnd - profileBegin);
1303 1722
1304 returnMass = _density * volume; 1723 returnMass = Density * BSParam.DensityScaleFactor * volume;
1305 1724 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1306 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1307 if (IsRootOfLinkset)
1308 {
1309 foreach (BSPrim prim in _childrenPrims)
1310 {
1311 returnMass += prim.CalculateMass();
1312 }
1313 }
1314 */
1315
1316 if (returnMass <= 0)
1317 returnMass = 0.0001f;
1318 1725
1319 if (returnMass > PhysicsScene.MaximumObjectMass) 1726 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1727
1322 return returnMass; 1728 return returnMass;
1323 }// end CalculateMass 1729 }// end CalculateMass
@@ -1326,135 +1732,73 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1732 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1733 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1734 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1735 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1736 {
1331 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt.
1333 bool needToRestoreLinkset = false;
1334 bool needToRestoreVehicle = false;
1335
1336 // Create the correct physical representation for this type of object. 1737 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1738 // Updates base.PhysBody and base.PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1739 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed. 1740 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1741 {
1342 // Called if the current prim body is about to be destroyed. 1742 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1743 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1744 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1745 RemoveBodyDependencies();
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 }); 1746 });
1348 1747
1349 if (needToRestoreLinkset)
1350 {
1351 // If physical body dependencies were removed, restore them
1352 Linkset.RestoreBodyDependencies(this);
1353 }
1354 if (needToRestoreVehicle)
1355 {
1356 // If physical body dependencies were removed, restore them
1357 _vehicle.RestoreBodyDependencies(this);
1358 }
1359
1360 // Make sure the properties are set on the new object 1748 // Make sure the properties are set on the new object
1361 UpdatePhysicalParameters(); 1749 UpdatePhysicalParameters();
1362 return; 1750 return;
1363 } 1751 }
1364 1752
1365 // The physics engine says that properties have updated. Update same and inform 1753 protected virtual void RemoveBodyDependencies()
1366 // the world that things have changed. 1754 {
1367 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() 1755 VehicleController.RemoveBodyDependencies(this);
1368 enum UpdatedProperties {
1369 Position = 1 << 0,
1370 Rotation = 1 << 1,
1371 Velocity = 1 << 2,
1372 Acceleration = 1 << 3,
1373 RotationalVel = 1 << 4
1374 } 1756 }
1375 1757
1376 const float ROTATION_TOLERANCE = 0.01f; 1758 // The physics engine says that properties have updated. Update same and inform
1377 const float VELOCITY_TOLERANCE = 0.001f; 1759 // the world that things have changed.
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) 1760 public override void UpdateProperties(EntityProperties entprop)
1383 { 1761 {
1384 /* 1762 TriggerPreUpdatePropertyAction(ref entprop);
1385 UpdatedProperties changed = 0; 1763
1386 // assign to the local variables so the normal set action does not happen 1764 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1387 // if (_position != entprop.Position) 1765 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) 1766 if (VehicleController.IsActive)
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 { 1767 {
1419 // Only update the position of single objects and linkset roots 1768 entprop.RotationalVelocity = OMV.Vector3.Zero;
1420 if (Linkset.IsRoot(this))
1421 {
1422 base.RequestPhysicsterseUpdate();
1423 }
1424 } 1769 }
1425 */
1426 1770
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1771 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1428 1772
1429 // Updates only for individual prims and for the root object of a linkset. 1773 // Assign directly to the local variables so the normal set actions do not happen
1430 if (Linkset.IsRoot(this)) 1774 _position = entprop.Position;
1431 { 1775 _orientation = entprop.Rotation;
1432 // Assign directly to the local variables so the normal set action does not happen 1776 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1433 _position = entprop.Position; 1777 // very sensitive to velocity changes.
1434 _orientation = entprop.Rotation; 1778 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold))
1435 _velocity = entprop.Velocity; 1779 _velocity = entprop.Velocity;
1436 _acceleration = entprop.Acceleration; 1780 _acceleration = entprop.Acceleration;
1437 _rotationalVelocity = entprop.RotationalVelocity; 1781 _rotationalVelocity = entprop.RotationalVelocity;
1438 1782
1439 // The sanity check can change the velocity and/or position. 1783 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1440 if (PositionSanityCheck(true))
1441 {
1442 entprop.Position = _position;
1443 entprop.Velocity = _velocity;
1444 }
1445 1784
1446 // remember the current and last set values 1785 // The sanity check can change the velocity and/or position.
1447 LastEntityProperties = CurrentEntityProperties; 1786 if (PositionSanityCheck(true /* inTaintTime */ ))
1448 CurrentEntityProperties = entprop; 1787 {
1788 entprop.Position = _position;
1789 entprop.Velocity = _velocity;
1790 entprop.RotationalVelocity = _rotationalVelocity;
1791 entprop.Acceleration = _acceleration;
1792 }
1449 1793
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; 1794 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1795 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453 1796
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1797 // remember the current and last set values
1798 LastEntityProperties = CurrentEntityProperties;
1799 CurrentEntityProperties = entprop;
1455 1800
1456 base.RequestPhysicsterseUpdate(); 1801 base.RequestPhysicsterseUpdate();
1457 }
1458 /* 1802 /*
1459 else 1803 else
1460 { 1804 {
@@ -1464,9 +1808,6 @@ public sealed class BSPrim : BSPhysObject
1464 entprop.Acceleration, entprop.RotationalVelocity); 1808 entprop.Acceleration, entprop.RotationalVelocity);
1465 } 1809 }
1466 */ 1810 */
1467
1468 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this);
1470 } 1811 }
1471} 1812}
1472} 1813}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
new file mode 100755
index 0000000..f1c3b5c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.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 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.Framework;
39using OpenSim.Region.Physics.Manager;
40
41using OMV = OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public class BSPrimDisplaced : BSPrim
46{
47 // The purpose of this module is to do any mapping between what the simulator thinks
48 // the prim position and orientation is and what the physical position/orientation.
49 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
50 // of the prim/linkset. The simulator tracks the location of the prim/linkset by
51 // the location of the root prim. So, if center-of-mass is anywhere but the origin
52 // of the root prim, the physical origin is displaced from the simulator origin.
53 //
54 // This routine works by capturing the Force* setting of position/orientation/... and
55 // adjusting the simulator values (being set) into the physical values.
56 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
57 //
58 // The updateParameter call is also captured and the values from the physics engine
59 // are converted into simulator origin values before being passed to the base
60 // class.
61
62 public virtual OMV.Vector3 PositionDisplacement { get; set; }
63 public virtual OMV.Quaternion OrientationDisplacement { get; set; }
64
65 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
66 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
67 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
68 {
69 ClearDisplacement();
70 }
71
72 public void ClearDisplacement()
73 {
74 PositionDisplacement = OMV.Vector3.Zero;
75 OrientationDisplacement = OMV.Quaternion.Identity;
76 }
77
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement)
82 {
83 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass;
86 else
87 comDisp = centerOfMassDisplacement;
88
89 if (comDisp == Vector3.Zero)
90 {
91 // If there is no diplacement. Things get reset.
92 PositionDisplacement = OMV.Vector3.Zero;
93 OrientationDisplacement = OMV.Quaternion.Identity;
94 }
95 else
96 {
97 // Remember the displacement from root as well as the origional rotation of the
98 // new center-of-mass.
99 PositionDisplacement = comDisp;
100 OrientationDisplacement = OMV.Quaternion.Identity;
101 }
102 }
103
104 public override Vector3 ForcePosition
105 {
106 get { return base.ForcePosition; }
107 set
108 {
109 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation);
111 else
112 base.ForcePosition = value;
113 }
114 }
115
116 public override Quaternion ForceOrientation
117 {
118 get { return base.ForceOrientation; }
119 set
120 {
121 base.ForceOrientation = value;
122 }
123 }
124
125 // TODO: decide if this is the right place for these variables.
126 // Somehow incorporate the optional settability by the user.
127 // Is this used?
128 public override OMV.Vector3 CenterOfMass
129 {
130 get { return RawPosition; }
131 }
132
133 // Is this used?
134 public override OMV.Vector3 GeometricCenter
135 {
136 get { return RawPosition; }
137 }
138
139 public override void UpdateProperties(EntityProperties entprop)
140 {
141 // Undo any center-of-mass displacement that might have been done.
142 if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
143 {
144 // Correct for any rotation around the center-of-mass
145 // TODO!!!
146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation);
147 // entprop.Rotation = something;
148 }
149
150 base.UpdateProperties(entprop);
151 }
152}
153}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
new file mode 100755
index 0000000..d65d407
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -0,0 +1,182 @@
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.Linq;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OMV = OpenMetaverse;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public class BSPrimLinkable : BSPrimDisplaced
39{
40 public BSLinkset Linkset { get; set; }
41 // The index of this child prim.
42 public int LinksetChildIndex { get; set; }
43
44 public BSLinksetInfo LinksetInfo { get; set; }
45
46 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
49 {
50 Linkset = BSLinkset.Factory(PhysicsScene, this);
51
52 PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
53 {
54 Linkset.Refresh(this);
55 });
56 }
57
58 public override void Destroy()
59 {
60 Linkset = Linkset.RemoveMeFromLinkset(this);
61 base.Destroy();
62 }
63
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj)
68 {
69 BSPrimLinkable parent = obj as BSPrimLinkable;
70 if (parent != null)
71 {
72 BSPhysObject parentBefore = Linkset.LinksetRoot;
73 int childrenBefore = Linkset.NumberOfChildren;
74
75 Linkset = parent.Linkset.AddMeToLinkset(this);
76
77 DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
78 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
79 }
80 return;
81 }
82
83 public override void delink()
84 {
85 // TODO: decide if this parent checking needs to happen at taint time
86 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
87
88 BSPhysObject parentBefore = Linkset.LinksetRoot;
89 int childrenBefore = Linkset.NumberOfChildren;
90
91 Linkset = Linkset.RemoveMeFromLinkset(this);
92
93 DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
94 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
95 return;
96 }
97
98 // When simulator changes position, this might be moving a child of the linkset.
99 public override OMV.Vector3 Position
100 {
101 get { return base.Position; }
102 set
103 {
104 base.Position = value;
105 PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
106 {
107 Linkset.UpdateProperties(UpdatedProperties.Position, this);
108 });
109 }
110 }
111
112 // When simulator changes orientation, this might be moving a child of the linkset.
113 public override OMV.Quaternion Orientation
114 {
115 get { return base.Orientation; }
116 set
117 {
118 base.Orientation = value;
119 PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
120 {
121 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
122 });
123 }
124 }
125
126 public override float TotalMass
127 {
128 get { return Linkset.LinksetMass; }
129 }
130
131 public override void UpdatePhysicalParameters()
132 {
133 base.UpdatePhysicalParameters();
134 // Recompute any linkset parameters.
135 // When going from non-physical to physical, this re-enables the constraints that
136 // had been automatically disabled when the mass was set to zero.
137 // For compound based linksets, this enables and disables interactions of the children.
138 if (Linkset != null) // null can happen during initialization
139 Linkset.Refresh(this);
140 }
141
142 protected override void MakeDynamic(bool makeStatic)
143 {
144 base.MakeDynamic(makeStatic);
145 if (makeStatic)
146 Linkset.MakeStatic(this);
147 else
148 Linkset.MakeDynamic(this);
149 }
150
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies()
153 {
154 Linkset.RemoveBodyDependencies(this);
155 base.RemoveBodyDependencies();
156 }
157
158 public override void UpdateProperties(EntityProperties entprop)
159 {
160 if (Linkset.IsRoot(this))
161 {
162 // Properties are only updated for the roots of a linkset.
163 // TODO: this will have to change when linksets are articulated.
164 base.UpdateProperties(entprop);
165 }
166 // The linkset might like to know about changing locations
167 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
168 }
169
170 public override bool Collide(uint collidingWith, BSPhysObject collidee,
171 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
172 {
173 // prims in the same linkset cannot collide with each other
174 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
175 if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
176 {
177 return false;
178 }
179 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
180 }
181}
182}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..e6aefd5 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -26,6 +26,8 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Linq;
30using System.Reflection;
29using System.Runtime.InteropServices; 31using System.Runtime.InteropServices;
30using System.Text; 32using System.Text;
31using System.Threading; 33using System.Threading;
@@ -38,40 +40,22 @@ using Nini.Config;
38using log4net; 40using log4net;
39using OpenMetaverse; 41using OpenMetaverse;
40 42
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 43namespace OpenSim.Region.Physics.BulletSPlugin
64{ 44{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 45public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 46{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 47 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 48 internal static readonly string LogHeader = "[BULLETS SCENE]";
69 49
70 // The name of the region we're working for. 50 // The name of the region we're working for.
71 public string RegionName { get; private set; } 51 public string RegionName { get; private set; }
72 52
73 public string BulletSimVersion = "?"; 53 public string BulletSimVersion = "?";
74 54
55 // The handle to the underlying managed or unmanaged version of Bullet being used.
56 public string BulletEngineName { get; private set; }
57 public BSAPITemplate PE;
58
75 public Dictionary<uint, BSPhysObject> PhysObjects; 59 public Dictionary<uint, BSPhysObject> PhysObjects;
76 public BSShapeCollection Shapes; 60 public BSShapeCollection Shapes;
77 61
@@ -82,32 +66,29 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
82 // every tick so OpenSim will update its animation. 66 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 67 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
84 68
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 69 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } } 70 public ILog Logger { get { return m_log; } }
91 71
92 public IMesher mesher; 72 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; } 73 public uint WorldID { get; private set; }
100 public BulletSim World { get; private set; } 74 public BulletWorld World { get; private set; }
101 75
102 // All the constraints that have been allocated in this instance. 76 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; } 77 public BSConstraintCollection Constraints { get; private set; }
104 78
105 // Simulation parameters 79 // Simulation parameters
106 private int m_maxSubSteps; 80 internal int m_maxSubSteps;
107 private float m_fixedTimeStep; 81 internal float m_fixedTimeStep;
108 private long m_simulationStep = 0; 82 internal long m_simulationStep = 0;
83 internal float NominalFrameRate { get; set; }
109 public long SimulationStep { get { return m_simulationStep; } } 84 public long SimulationStep { get { return m_simulationStep; } }
110 private 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 PostStepAction 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 int 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,13 +423,18 @@ 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)
427 { 434 {
428 if (!m_initialized) return; 435 if (!m_initialized) return;
429 436
430 BSPrim bsprim = prim as BSPrim; 437 BSPhysObject bsprim = prim as BSPhysObject;
431 if (bsprim != null) 438 if (bsprim != null)
432 { 439 {
433 DetailLog("{0},RemovePrim,call", bsprim.LocalID); 440 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
@@ -456,9 +463,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
456 463
457 if (!m_initialized) return null; 464 if (!m_initialized) return null;
458 465
459 DetailLog("{0},AddPrimShape,call", localID); 466 DetailLog("{0},BSScene.AddPrimShape,call", localID);
460 467
461 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 468 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
462 lock (PhysObjects) PhysObjects.Add(localID, prim); 469 lock (PhysObjects) PhysObjects.Add(localID, prim);
463 return prim; 470 return prim;
464 } 471 }
@@ -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
490 ProcessTaints(); 500 ProcessTaints();
491 501
492 // Some of the prims operate with special vehicle properties 502 // Some of the physical objects requre individual, pre-step calls
493 ProcessVehicles(timeStep); 503 // (vehicles and avatar movement, in particular)
494 ProcessTaints(); // the vehicles might have added taints 504 TriggerPreStepEvent(timeStep);
505
506 // the prestep actions might have added taints
507 numTaints += _taintOperations.Count;
508 ProcessTaints();
509
510 InTaintTime = false; // Only used for debugging so locking is not necessary.
511
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 (PhysicsMetricDumpFrames != 0 && ((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.
@@ -535,8 +558,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
535 uint cB = m_collisionArray[ii].bID; 558 uint cB = m_collisionArray[ii].bID;
536 Vector3 point = m_collisionArray[ii].point; 559 Vector3 point = m_collisionArray[ii].point;
537 Vector3 normal = m_collisionArray[ii].normal; 560 Vector3 normal = m_collisionArray[ii].normal;
538 SendCollision(cA, cB, point, normal, 0.01f); 561 float penetration = m_collisionArray[ii].penetration;
539 SendCollision(cB, cA, point, -normal, 0.01f); 562 SendCollision(cA, cB, point, normal, penetration);
563 SendCollision(cB, cA, point, -normal, penetration);
540 } 564 }
541 } 565 }
542 566
@@ -562,12 +586,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 586
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 587 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 588 // Not done above because it is inside an iteration of ObjectWithCollisions.
589 // This complex collision processing is required to create an empty collision
590 // event call after all real collisions have happened on an object. This enables
591 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 592 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 593 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 594 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 595 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 596 ObjectsWithNoMoreCollisions.Clear();
570 } 597 }
598 // Done with collisions.
571 599
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 600 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 601 if (updatedEntityCount > 0)
@@ -583,17 +611,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
583 } 611 }
584 } 612 }
585 613
586 ProcessPostStepTaints(); 614 TriggerPostStepEvent(timeStep);
587 615
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 616 // 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. 617 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 618 if (m_physicsPhysicalDumpEnabled)
619 PE.DumpAllInfo(World);
591 620
592 // The physics engine returns the number of milliseconds it simulated this call. 621 // 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. 622 // 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). 623 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 624 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
596 // return timeStep * 1000 * 55;
597 } 625 }
598 626
599 // Something has collided 627 // Something has collided
@@ -639,12 +667,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 667
640 public override void SetWaterLevel(float baseheight) 668 public override void SetWaterLevel(float baseheight)
641 { 669 {
642 m_waterLevel = baseheight; 670 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 671 }
649 672
650 public override void DeleteTerrain() 673 public override void DeleteTerrain()
@@ -675,12 +698,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
675 698
676 public override Dictionary<uint, float> GetTopColliders() 699 public override Dictionary<uint, float> GetTopColliders()
677 { 700 {
678 return new Dictionary<uint, float>(); 701 Dictionary<uint, float> topColliders;
702
703 lock (PhysObjects)
704 {
705 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
706 {
707 kvp.Value.ComputeCollisionScore();
708 }
709
710 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
711 orderedPrims.OrderByDescending(p => p.CollisionScore);
712 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
713 }
714
715 return topColliders;
679 } 716 }
680 717
681 public override bool IsThreaded { get { return false; } } 718 public override bool IsThreaded { get { return false; } }
682 719
683 #region Taints 720 #region Taints
721 // The simulation execution order is:
722 // Simulate()
723 // DoOneTimeTaints
724 // TriggerPreStepEvent
725 // DoOneTimeTaints
726 // Step()
727 // ProcessAndSendToSimulatorCollisions
728 // ProcessAndSendToSimulatorPropertyUpdates
729 // TriggerPostStepEvent
684 730
685 // Calls to the PhysicsActors can't directly call into the physics engine 731 // 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. 732 // because it might be busy. We delay changes to a known time.
@@ -707,58 +753,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 TaintedObject(ident, callback); 753 TaintedObject(ident, callback);
708 } 754 }
709 755
756 private void TriggerPreStepEvent(float timeStep)
757 {
758 PreStepAction actions = BeforeStep;
759 if (actions != null)
760 actions(timeStep);
761
762 }
763
764 private void TriggerPostStepEvent(float timeStep)
765 {
766 PostStepAction actions = AfterStep;
767 if (actions != null)
768 actions(timeStep);
769
770 }
771
710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 772 // 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 773 // 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. 774 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 775 public void ProcessTaints()
714 { 776 {
715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 777 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 778 ProcessPostTaintTaints();
718 InTaintTime = false;
719 } 779 }
720 780
721 private void ProcessRegularTaints() 781 private void ProcessRegularTaints()
722 { 782 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 783 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
724 { 784 {
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 785 // swizzle a new list into the list location so we can process what's there
763 List<TaintCallbackEntry> oldList; 786 List<TaintCallbackEntry> oldList;
764 lock (_taintLock) 787 lock (_taintLock)
@@ -797,6 +820,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
797 return; 820 return;
798 } 821 }
799 822
823 // Taints that happen after the normal taint processing but before the simulation step.
800 private void ProcessPostTaintTaints() 824 private void ProcessPostTaintTaints()
801 { 825 {
802 if (_postTaintOperations.Count > 0) 826 if (_postTaintOperations.Count > 0)
@@ -824,45 +848,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
824 } 848 }
825 } 849 }
826 850
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. 851 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 852 public bool AssertInTaintTime(string whereFrom)
868 { 853 {
@@ -870,517 +855,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
870 { 855 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 856 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); 857 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. 858 // Util.PrintCallStack(DetailLog);
874 } 859 }
875 return InTaintTime; 860 return InTaintTime;
876 } 861 }
877 862
878 #endregion // Taints 863 #endregion // Taints
879 864
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
930
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 865 #region IPhysicsParameters
1379 // Get the list of parameters this physics engine supports 866 // Get the list of parameters this physics engine supports
1380 public PhysParameterEntry[] GetParameterList() 867 public PhysParameterEntry[] GetParameterList()
1381 { 868 {
1382 BuildParameterTable(); 869 BSParam.BuildParameterTable();
1383 return SettableParameters; 870 return BSParam.SettableParameters;
1384 } 871 }
1385 872
1386 // Set parameter on a specific or all instances. 873 // Set parameter on a specific or all instances.
@@ -1389,63 +876,65 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1389 // will use the next time since it's pinned and shared memory. 876 // will use the next time since it's pinned and shared memory.
1390 // Some of the values require calling into the physics engine to get the new 877 // Some of the values require calling into the physics engine to get the new
1391 // value activated ('terrainFriction' for instance). 878 // value activated ('terrainFriction' for instance).
1392 public bool SetPhysicsParameter(string parm, float val, uint localID) 879 public bool SetPhysicsParameter(string parm, string val, uint localID)
1393 { 880 {
1394 bool ret = false; 881 bool ret = false;
1395 ParameterDefn theParam; 882
1396 if (TryGetParameter(parm, out theParam)) 883 BSParam.ParameterDefnBase theParam;
884 if (BSParam.TryGetParameter(parm, out theParam))
1397 { 885 {
1398 theParam.setter(this, parm, localID, val); 886 // Set the value in the C# code
887 theParam.SetValue(this, val);
888
889 // Optionally set the parameter in the unmanaged code
890 if (theParam.HasSetOnObject)
891 {
892 // update all the localIDs specified
893 // If the local ID is APPLY_TO_NONE, just change the default value
894 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
895 // If the localID is a specific object, apply the parameter change to only that object
896 List<uint> objectIDs = new List<uint>();
897 switch (localID)
898 {
899 case PhysParameterEntry.APPLY_TO_NONE:
900 // This will cause a call into the physical world if some operation is specified (SetOnObject).
901 objectIDs.Add(TERRAIN_ID);
902 TaintedUpdateParameter(parm, objectIDs, val);
903 break;
904 case PhysParameterEntry.APPLY_TO_ALL:
905 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
906 TaintedUpdateParameter(parm, objectIDs, val);
907 break;
908 default:
909 // setting only one localID
910 objectIDs.Add(localID);
911 TaintedUpdateParameter(parm, objectIDs, val);
912 break;
913 }
914 }
915
1399 ret = true; 916 ret = true;
1400 } 917 }
1401 return ret; 918 return ret;
1402 } 919 }
1403 920
1404 // update all the localIDs specified
1405 // 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
1407 // 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)
1409 {
1410 List<uint> objectIDs = new List<uint>();
1411 switch (localID)
1412 {
1413 case PhysParameterEntry.APPLY_TO_NONE:
1414 defaultLoc = val; // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val);
1418 break;
1419 case PhysParameterEntry.APPLY_TO_ALL:
1420 defaultLoc = val; // setting ALL also sets the default value
1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1422 TaintedUpdateParameter(parm, objectIDs, val);
1423 break;
1424 default:
1425 // setting only one localID
1426 objectIDs.Add(localID);
1427 TaintedUpdateParameter(parm, objectIDs, val);
1428 break;
1429 }
1430 }
1431
1432 // schedule the actual updating of the paramter to when the phys engine is not busy 921 // schedule the actual updating of the paramter to when the phys engine is not busy
1433 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) 922 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1434 { 923 {
1435 float xval = val; 924 string xval = val;
1436 List<uint> xlIDs = lIDs; 925 List<uint> xlIDs = lIDs;
1437 string xparm = parm; 926 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() { 927 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam; 928 BSParam.ParameterDefnBase thisParam;
1440 if (TryGetParameter(xparm, out thisParam)) 929 if (BSParam.TryGetParameter(xparm, out thisParam))
1441 { 930 {
1442 if (thisParam.onObject != null) 931 if (thisParam.HasSetOnObject)
1443 { 932 {
1444 foreach (uint lID in xlIDs) 933 foreach (uint lID in xlIDs)
1445 { 934 {
1446 BSPhysObject theObject = null; 935 BSPhysObject theObject = null;
1447 PhysObjects.TryGetValue(lID, out theObject); 936 if (PhysObjects.TryGetValue(lID, out theObject))
1448 thisParam.onObject(this, theObject, xval); 937 thisParam.SetOnObject(this, theObject);
1449 } 938 }
1450 } 939 }
1451 } 940 }
@@ -1454,14 +943,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1454 943
1455 // Get parameter. 944 // Get parameter.
1456 // Return 'false' if not able to get the parameter. 945 // Return 'false' if not able to get the parameter.
1457 public bool GetPhysicsParameter(string parm, out float value) 946 public bool GetPhysicsParameter(string parm, out string value)
1458 { 947 {
1459 float val = 0f; 948 string val = String.Empty;
1460 bool ret = false; 949 bool ret = false;
1461 ParameterDefn theParam; 950 BSParam.ParameterDefnBase theParam;
1462 if (TryGetParameter(parm, out theParam)) 951 if (BSParam.TryGetParameter(parm, out theParam))
1463 { 952 {
1464 val = theParam.getter(this); 953 val = theParam.GetValue(this);
1465 ret = true; 954 ret = true;
1466 } 955 }
1467 value = val; 956 value = val;
@@ -1470,24 +959,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1470 959
1471 #endregion IPhysicsParameters 960 #endregion IPhysicsParameters
1472 961
1473 #endregion Runtime settable parameters
1474
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. 962 // Invoke the detailed logger and output something if it's enabled.
1486 public void DetailLog(string msg, params Object[] args) 963 public void DetailLog(string msg, params Object[] args)
1487 { 964 {
1488 PhysicsLogging.Write(msg, args); 965 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 966 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 967 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 968 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 969 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 970 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..220fbbc 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");
@@ -109,8 +116,7 @@ public sealed class BSShapeCollection : IDisposable
109 // rebuild the body around it. 116 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body 117 // Updates prim.BSBody with information/pointers to requested body
111 // Returns 'true' if BSBody was changed. 118 // Returns 'true' if BSBody was changed.
112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback);
113 prim.PhysShape, bodyCallback);
114 ret = newGeom || newBody; 120 ret = newGeom || newBody;
115 } 121 }
116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -119,51 +125,52 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 125 return ret;
120 } 126 }
121 127
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
131 }
132
122 // Track another user of a body. 133 // Track another user of a body.
123 // We presume the caller has allocated the body. 134 // 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. 135 // Bodies only have one user so the body is just put into the world if not already there.
125 public void ReferenceBody(BulletBody body, bool inTaintTime) 136 private void ReferenceBody(BulletBody body)
126 { 137 {
127 lock (m_collectionActivityLock) 138 lock (m_collectionActivityLock)
128 { 139 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
131 { 142 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
133 { 144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 145 }
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 }
137 });
138 } 146 }
139 } 147 }
140 148
141 // Release the usage of a body. 149 // Release the usage of a body.
142 // Called when releasing use of a BSBody. BSShape is handled separately. 150 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
144 { 153 {
145 if (body.ptr == IntPtr.Zero) 154 if (!body.HasPhysicalBody)
146 return; 155 return;
147 156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
148 lock (m_collectionActivityLock) 159 lock (m_collectionActivityLock)
149 { 160 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
151 { 162 // If the caller needs to know the old body is going away, pass the event up.
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 163 if (bodyCallback != null) bodyCallback(body);
153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body);
156 164
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 165 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 166 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 167 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 168 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 169 }
162 170
163 // Zero any reference to the shape so it is not freed when the body is deleted. 171 // 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); 172 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 173 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 });
167 } 174 }
168 } 175 }
169 176
@@ -184,17 +191,17 @@ public sealed class BSShapeCollection : IDisposable
184 { 191 {
185 // There is an existing instance of this mesh. 192 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 193 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 196 }
190 else 197 else
191 { 198 {
192 // This is a new reference to a mesh 199 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 200 meshDesc.shape = shape.Clone();
194 meshDesc.shapeKey = shape.shapeKey; 201 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 202 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 203 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 206 ret = true;
200 } 207 }
@@ -207,16 +214,16 @@ public sealed class BSShapeCollection : IDisposable
207 { 214 {
208 // There is an existing instance of this hull. 215 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 216 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 219 }
213 else 220 else
214 { 221 {
215 // This is a new reference to a hull 222 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 223 hullDesc.shape = shape.Clone();
217 hullDesc.shapeKey = shape.shapeKey; 224 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 225 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 228 ret = true;
222 229
@@ -234,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable
234 } 241 }
235 242
236 // Release the usage of a shape. 243 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 244 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback)
238 { 245 {
239 if (shape.ptr == IntPtr.Zero) 246 if (!shape.HasPhysicalShape)
240 return; 247 return;
241 248
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 249 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
250
251 if (shape.HasPhysicalShape)
243 { 252 {
244 if (shape.ptr != IntPtr.Zero) 253 if (shape.isNativeShape)
245 { 254 {
246 if (shape.isNativeShape) 255 // Native shapes are not tracked and are released immediately
247 { 256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
248 // Native shapes are not tracked and are released immediately 257 BSScene.DetailLogZero, shape.AddrString);
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 if (shapeCallback != null) shapeCallback(shape);
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 259 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
251 if (shapeCallback != null) shapeCallback(shape); 260 }
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 else
253 } 262 {
254 else 263 switch (shape.type)
255 { 264 {
256 switch (shape.type) 265 case BSPhysicsShapeType.SHAPE_HULL:
257 { 266 DereferenceHull(shape, shapeCallback);
258 case BSPhysicsShapeType.SHAPE_HULL: 267 break;
259 DereferenceHull(shape, shapeCallback); 268 case BSPhysicsShapeType.SHAPE_MESH:
260 break; 269 DereferenceMesh(shape, shapeCallback);
261 case BSPhysicsShapeType.SHAPE_MESH: 270 break;
262 DereferenceMesh(shape, shapeCallback); 271 case BSPhysicsShapeType.SHAPE_COMPOUND:
263 break; 272 DereferenceCompound(shape, shapeCallback);
264 case BSPhysicsShapeType.SHAPE_COMPOUND: 273 break;
265 DereferenceCompound(shape, shapeCallback); 274 case BSPhysicsShapeType.SHAPE_UNKNOWN:
266 break; 275 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN: 276 default:
268 break; 277 break;
269 default:
270 break;
271 }
272 } 278 }
273 } 279 }
274 }); 280 }
275 } 281 }
276 282
277 // Count down the reference count for a mesh shape 283 // Count down the reference count for a mesh shape
@@ -286,7 +292,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 292 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 293 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 294 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 295 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 296 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 297
292 } 298 }
@@ -307,7 +313,7 @@ public sealed class BSShapeCollection : IDisposable
307 313
308 hullDesc.lastReferenced = System.DateTime.Now; 314 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 315 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 316 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 317 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 318 }
313 } 319 }
@@ -320,57 +326,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 326 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 327 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 328 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 329 if (!PhysicsScene.PE.IsCompound(shape))
324 { 330 {
325 // Failed the sanity check!! 331 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 332 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")); 333 LogHeader, shape.type, shape.AddrString);
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 334 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 335 BSScene.DetailLogZero, shape.type, shape.AddrString);
330 return; 336 return;
331 } 337 }
332 338
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 339 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 341
336 for (int ii = numChildren - 1; ii >= 0; ii--) 342 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 343 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 344 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 345 DereferenceAnonCollisionShape(childShape);
340 } 346 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 347 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 348 }
343 349
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 350 // 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. 351 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 352 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 353 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 354 {
349 MeshDesc meshDesc; 355 MeshDesc meshDesc;
350 HullDesc hullDesc; 356 HullDesc hullDesc;
351 357
352 BulletShape shapeInfo = new BulletShape(cShape); 358 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 359 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 360 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 361 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 362 }
358 else 363 else
359 { 364 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 365 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 366 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 367 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 368 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 369 }
365 else 370 else
366 { 371 {
367 if (BulletSimAPI.IsCompound2(cShape)) 372 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 373 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 374 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 375 }
371 else 376 else
372 { 377 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 378 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 379 {
375 shapeInfo.isNativeShape = true; 380 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 381 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,16 +384,16 @@ public sealed class BSShapeCollection : IDisposable
379 } 384 }
380 } 385 }
381 386
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 387 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 388
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 389 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 390 {
386 DereferenceShape(shapeInfo, true, null); 391 DereferenceShape(shapeInfo, null);
387 } 392 }
388 else 393 else
389 { 394 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 395 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 396 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 397 }
393 } 398 }
394 399
@@ -408,19 +413,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 413 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 414 {
410 // an avatar capsule is close to a native shape (it is not shared) 415 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 416 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 417 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; 418 ret = true;
415 haveShape = true; 419 haveShape = true;
416 } 420 }
417 421
418 // Compound shapes are handled special as they are rebuilt from scratch. 422 // 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. 423 // 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) 424 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 425 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 426 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 427 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 428 haveShape = true;
425 } 429 }
426 430
@@ -432,8 +436,9 @@ public sealed class BSShapeCollection : IDisposable
432 return ret; 436 return ret;
433 } 437 }
434 438
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 439 // Create a mesh, hull or native shape.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 440 // Return 'true' if the prim's shape was changed.
441 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 442 {
438 bool ret = false; 443 bool ret = false;
439 bool haveShape = false; 444 bool haveShape = false;
@@ -442,46 +447,48 @@ public sealed class BSShapeCollection : IDisposable
442 447
443 // If the prim attributes are simple, this could be a simple Bullet native shape 448 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 449 if (!haveShape
445 && pbs != null
446 && nativeShapePossible 450 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 451 && pbs != null
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 452 && !pbs.SculptEntry
449 && pbs.ProfileHollow == 0 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 454 {
451 && pbs.PathBegin == 0 && pbs.PathEnd == 0 455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
452 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 457 if (prim.PhysShape.HasPhysicalShape)
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 458 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
455 { 459
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 460 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
461 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
462
463 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 464 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 465 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 466 {
460 haveShape = true; 467 haveShape = true;
461 if (forceRebuild 468 if (forceRebuild
462 || prim.Scale != prim.Size 469 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 470 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 471 )
465 { 472 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 474 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 475 }
476 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
477 prim.LocalID, forceRebuild, ret, prim.PhysShape);
471 } 478 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 479 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 { 480 {
474 haveShape = true; 481 haveShape = true;
475 if (forceRebuild 482 if (forceRebuild
476 || prim.Scale != prim.Size 483 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 484 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 485 )
479 { 486 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 488 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 489 }
490 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
491 prim.LocalID, forceRebuild, ret, prim.PhysShape);
485 } 492 }
486 } 493 }
487 494
@@ -494,23 +501,36 @@ public sealed class BSShapeCollection : IDisposable
494 return ret; 501 return ret;
495 } 502 }
496 503
504 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0
509 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
510 && pbs.PathBegin == 0 && pbs.PathEnd == 0
511 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
512 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
513 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
514 }
515
516 // return 'true' if the prim's shape was changed.
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 { 518 {
499 519
500 bool ret = false; 520 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 521 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 522 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 524 {
505 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim, shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 529 }
510 else 530 else
511 { 531 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 532 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 535 }
516 return ret; 536 return ret;
@@ -523,14 +543,15 @@ public sealed class BSShapeCollection : IDisposable
523 ShapeDestructionCallback shapeCallback) 543 ShapeDestructionCallback shapeCallback)
524 { 544 {
525 // release any previous shape 545 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback); 546 DereferenceShape(prim.PhysShape, shapeCallback);
527 547
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 549
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 552 prim.LocalID, newShape, prim.Scale);
533 553
554 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 555 prim.PhysShape = newShape;
535 return true; 556 return true;
536 } 557 }
@@ -550,20 +571,17 @@ public sealed class BSShapeCollection : IDisposable
550 571
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 573 {
553 // The proper scale has been calculated in the prim. 574
554 newShape = new BulletShape( 575 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 576 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 577 }
559 else 578 else
560 { 579 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 580 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 581 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 582
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 583 }
566 if (newShape.ptr == IntPtr.Zero) 584 if (!newShape.HasPhysicalShape)
567 { 585 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 586 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 587 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +598,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 598 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 599 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 600 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 601 BulletShape newShape = new BulletShape();
584 602
585 float lod; 603 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 604 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,62 +607,96 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 607 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 608 return false;
591 609
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 610 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 611 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
594 612
595 // Since we're recreating new, get rid of the reference to the previous shape 613 // Since we're recreating new, get rid of the reference to the previous shape
596 DereferenceShape(prim.PhysShape, true, shapeCallback); 614 DereferenceShape(prim.PhysShape, shapeCallback);
597 615
598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 616 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
599 // Take evasive action if the mesh was not constructed. 617 // Take evasive action if the mesh was not constructed.
600 newShape = VerifyMeshCreated(newShape, prim); 618 newShape = VerifyMeshCreated(newShape, prim);
601 619
602 ReferenceShape(newShape); 620 ReferenceShape(newShape);
603 621
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 622 prim.PhysShape = newShape;
607 623
608 return true; // 'true' means a new shape has been added to this prim 624 return true; // 'true' means a new shape has been added to this prim
609 } 625 }
610 626
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 627 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 628 {
613 IMesh meshData = null; 629 BulletShape newShape = new BulletShape();
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 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 640 true,
641 false, // say it is not physical so a bounding box is not built
642 false, // do not cache the mesh and do not use previously built versions
643 false // It's NOT for ODE
644 );
625 645
626 if (meshData != null) 646 if (meshData != null)
627 { 647 {
648
628 int[] indices = meshData.getIndexListAsInt(); 649 int[] indices = meshData.getIndexListAsInt();
629 List<OMV.Vector3> vertices = meshData.getVertexList(); 650 int realIndicesIndex = indices.Length;
651 float[] verticesAsFloats = meshData.getVertexListAsFloat();
630 652
631 float[] verticesAsFloats = new float[vertices.Count * 3]; 653 if (BSParam.ShouldRemoveZeroWidthTriangles)
632 int vi = 0;
633 foreach (OMV.Vector3 vv in vertices)
634 { 654 {
635 verticesAsFloats[vi++] = vv.X; 655 // Remove degenerate triangles. These are triangles with two of the vertices
636 verticesAsFloats[vi++] = vv.Y; 656 // are the same. This is complicated by the problem that vertices are not
637 verticesAsFloats[vi++] = vv.Z; 657 // made unique in sculpties so we have to compare the values in the vertex.
658 realIndicesIndex = 0;
659 for (int tri = 0; tri < indices.Length; tri += 3)
660 {
661 // Compute displacements into vertex array for each vertex of the triangle
662 int v1 = indices[tri + 0] * 3;
663 int v2 = indices[tri + 1] * 3;
664 int v3 = indices[tri + 2] * 3;
665 // Check to see if any two of the vertices are the same
666 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
667 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
668 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
669 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
670 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
671 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
672 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
673 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
674 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
675 )
676 {
677 // None of the vertices of the triangles are the same. This is a good triangle;
678 indices[realIndicesIndex + 0] = indices[tri + 0];
679 indices[realIndicesIndex + 1] = indices[tri + 1];
680 indices[realIndicesIndex + 2] = indices[tri + 2];
681 realIndicesIndex += 3;
682 }
683 }
638 } 684 }
685 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
686 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
639 687
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 688 if (realIndicesIndex != 0)
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 689 {
642 690 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 691 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 692 }
693 else
694 {
695 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
696 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
697 }
645 } 698 }
646 } 699 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 700 newShape.shapeKey = newMeshKey;
649 701
650 return newShape; 702 return newShape;
@@ -652,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
652 704
653 // See that hull shape exists in the physical world and update prim.BSShape. 705 // See that hull shape exists in the physical world and update prim.BSShape.
654 // We could be creating the hull because scale changed or whatever. 706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
656 { 709 {
657 BulletShape newShape; 710 BulletShape newShape;
@@ -663,19 +716,18 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 716 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 717 return false;
665 718
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 719 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 720 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 721
669 // Remove usage of the previous shape. 722 // Remove usage of the previous shape.
670 DereferenceShape(prim.PhysShape, true, shapeCallback); 723 DereferenceShape(prim.PhysShape, shapeCallback);
671 724
672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
673 newShape = VerifyMeshCreated(newShape, prim); 727 newShape = VerifyMeshCreated(newShape, prim);
674 728
675 ReferenceShape(newShape); 729 ReferenceShape(newShape);
676 730
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 731 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 732 return true; // 'true' means a new shape has been added to this prim
681 } 733 }
@@ -684,18 +736,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 736 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 737 {
686 738
739 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 740 IntPtr hullPtr = IntPtr.Zero;
741
688 HullDesc hullDesc; 742 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 744 {
691 // If the hull shape already is created, just use it. 745 // If the hull shape already has been created, just use the one shared instance.
692 hullPtr = hullDesc.ptr; 746 newShape = hullDesc.shape.Clone();
693 } 747 }
694 else 748 else
695 { 749 {
696 // Build a new hull in the physical world 750 // 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 751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 753 if (meshData != null)
700 { 754 {
701 755
@@ -714,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
714 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
715 } 769 }
716 770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
717 // setup and do convex hull conversion 783 // setup and do convex hull conversion
718 m_hulls = new List<ConvexResult>(); 784 m_hulls = new List<ConvexResult>();
719 DecompDesc dcomp = new DecompDesc(); 785 DecompDesc dcomp = new DecompDesc();
720 dcomp.mIndices = convIndices; 786 dcomp.mIndices = convIndices;
721 dcomp.mVertices = convVertices; 787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
722 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); 793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
723 // create the hull into the _hulls variable 794 // create the hull into the _hulls variable
724 convexBuilder.process(dcomp); 795 convexBuilder.process(dcomp);
725 796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
726 // Convert the vertices and indices for passing to unmanaged. 800 // Convert the vertices and indices for passing to unmanaged.
727 // The hull information is passed as a large floating point array. 801 // The hull information is passed as a large floating point array.
728 // The format is: 802 // The format is:
@@ -777,14 +851,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 851 }
778 } 852 }
779 // create the hull data structure in Bullet 853 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 854 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 855 }
782 } 856 }
783 857
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 858 newShape.shapeKey = newHullKey;
786 859
787 return newShape; // 'true' means a new shape has been added to this prim 860 return newShape;
788 } 861 }
789 862
790 // Callback from convex hull creater with a newly created hull. 863 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +876,12 @@ 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. 876 // 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); 877 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 878
806 BulletShape cShape = new BulletShape( 879 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808 880
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 881 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 882 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 883 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 884 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 885 prim.LocalID, cShape, prim.PhysShape);
814 886
815 prim.PhysShape = cShape; 887 prim.PhysShape = cShape;
@@ -822,14 +894,19 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 894 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 895 {
824 // level of detail based on size and type of the object 896 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 897 float lod = BSParam.MeshLOD;
898
899 // prims with curvy internal cuts need higher lod
900 if (pbs.HollowShape == HollowShape.Circle)
901 lod = BSParam.MeshCircularLOD;
902
826 if (pbs.SculptEntry) 903 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 904 lod = BSParam.SculptLOD;
828 905
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 906 // 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)); 907 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 908 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 909 lod = BSParam.MeshMegaPrimLOD;
833 910
834 retLod = lod; 911 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 912 return pbs.GetMeshKey(size, lod);
@@ -851,51 +928,88 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 928 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 929 {
853 // If the shape was successfully created, nothing more to do 930 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 931 if (newShape.HasPhysicalShape)
855 return newShape; 932 return newShape;
856 933
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
859 { 938 {
860 prim.LastAssetBuildFailed = true; 939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
861 BSPhysObject xprim = prim; 940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", 941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate
865 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
867 if (assetProvider != null)
868 {
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 {
872 if (!yprim.BaseShape.SculptEntry)
873 return;
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
875 return;
876
877 yprim.BaseShape.SculptData = asset.Data;
878 // This will cause the prim to see that the filler shape is not the right
879 // one and try again to build the object.
880 // No race condition with the normal shape setting since the rebuild is at taint time.
881 yprim.ForceBodyShapeRebuild(false);
882
883 });
884 }
885 });
886 } 942 }
887 else 943 else
888 { 944 {
889 if (prim.LastAssetBuildFailed) 945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
946 if (prim.BaseShape.SculptEntry
947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
890 { 951 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); 953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
955
956 BSPhysObject xprim = prim;
957 Util.FireAndForget(delegate
958 {
959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
960 if (assetProvider != null)
961 {
962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
964 {
965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
968 {
969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
970 {
971 yprim.BaseShape.SculptData = asset.Data;
972 // This will cause the prim to see that the filler shape is not the right
973 // one and try again to build the object.
974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
985 else
986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
989
990 });
991 }
992 else
993 {
994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
996 LogHeader, PhysicsScene.Name);
997 }
998 });
999 }
1000 else
1001 {
1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
893 } 1007 }
894 } 1008 }
895 1009
896 // While we figure out the real problem, stick a simple native shape on the object. 1010 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
897 BulletShape fillinShape = 1011 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 1012 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
899 1013
900 return fillinShape; 1014 return fillinShape;
901 } 1015 }
@@ -904,49 +1018,45 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 1018 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 1019 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 1020 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 1021 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback)
908 BodyDestructionCallback bodyCallback)
909 { 1022 {
910 bool ret = false; 1023 bool ret = false;
911 1024
912 // the mesh, hull or native shape must have already been created in Bullet 1025 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 1026 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 1027
915 // If there is an existing body, verify it's of an acceptable type. 1028 // 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. 1029 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 1030 if (!mustRebuild)
918 { 1031 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 1032 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 1033 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 1034 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 1035 {
923 // If the collisionObject is not the correct type for solidness, rebuild what's there 1036 // If the collisionObject is not the correct type for solidness, rebuild what's there
924 mustRebuild = true; 1037 mustRebuild = true;
1038 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
925 } 1039 }
926 } 1040 }
927 1041
928 if (mustRebuild || forceRebuild) 1042 if (mustRebuild || forceRebuild)
929 { 1043 {
930 // Free any old body 1044 // Free any old body
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 1045 DereferenceBody(prim.PhysBody, bodyCallback);
932 1046
933 BulletBody aBody; 1047 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 1048 if (prim.IsSolid)
936 { 1049 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 1050 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1051 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 } 1052 }
941 else 1053 else
942 { 1054 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 1055 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1056 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 } 1057 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 1058
949 ReferenceBody(aBody, true); 1059 ReferenceBody(aBody);
950 1060
951 prim.PhysBody = aBody; 1061 prim.PhysBody = aBody;
952 1062
@@ -956,13 +1066,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 1066 return ret;
957 } 1067 }
958 1068
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 1069 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 1070 {
961 bool ret = false; 1071 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 1072 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 1073 foreach (MeshDesc md in Meshes.Values)
964 { 1074 {
965 if (md.ptr == addr) 1075 if (md.shape.ReferenceSame(shape))
966 { 1076 {
967 foundDesc = md; 1077 foundDesc = md;
968 ret = true; 1078 ret = true;
@@ -974,13 +1084,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 1084 return ret;
975 } 1085 }
976 1086
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 1087 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 1088 {
979 bool ret = false; 1089 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 1090 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 1091 foreach (HullDesc hd in Hulls.Values)
982 { 1092 {
983 if (hd.ptr == addr) 1093 if (hd.shape.ReferenceSame(shape))
984 { 1094 {
985 foundDesc = hd; 1095 foundDesc = hd;
986 ret = true; 1096 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..b2fb835 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,41 +122,49 @@ 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 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
130 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 140
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 141 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
136 Vector3.Zero, Quaternion.Identity)); 142 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 143 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 144 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 145 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 146 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 147 m_groundPlane.ApplyCollisionMask(PhysicsScene);
144 148
145 // 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);
147 m_terrains.Add(Vector3.Zero, initialTerrain); 150 lock (m_terrains)
151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
148 } 155 }
149 156
150 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
152 { 159 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
161 if (m_groundPlane.HasPhysicalBody)
154 { 162 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
156 { 164 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 165 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
158 } 166 }
159 m_groundPlane.ptr = IntPtr.Zero; 167 m_groundPlane.Clear();
160 } 168 }
161 169
162 ReleaseTerrain(); 170 ReleaseTerrain();
@@ -165,17 +173,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 173 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 174 public void ReleaseTerrain()
167 { 175 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 176 lock (m_terrains)
169 { 177 {
170 kvp.Value.Dispose(); 178 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
179 {
180 kvp.Value.Dispose();
181 }
182 m_terrains.Clear();
171 } 183 }
172 m_terrains.Clear();
173 } 184 }
174 185
175 // The simulator wants to set a new heightmap for the terrain. 186 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 187 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 188 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 189 // If there are multiple requests for changes to the same terrain between ticks,
190 // only do that last one.
191 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 192 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 194 {
@@ -185,11 +198,16 @@ public sealed class BSTerrainManager
185 // the terrain is added to our parent 198 // the terrain is added to our parent
186 if (MegaRegionParentPhysicsScene is BSScene) 199 if (MegaRegionParentPhysicsScene is BSScene)
187 { 200 {
188 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
189 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 202 // This looks really odd but this region is passing its terrain to its mega-region root region
190 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 203 // and the creation of the terrain must happen on the root region's taint thread and not
191 BSScene.CHILDTERRAIN_ID, localHeightMap, 204 // my taint thread.
192 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 205 ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
206 {
207 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
208 BSScene.CHILDTERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
210 });
193 } 211 }
194 } 212 }
195 else 213 else
@@ -198,29 +216,30 @@ public sealed class BSTerrainManager
198 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 216 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
199 217
200 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 218 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
201 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 219 m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
202 } 220 }
203 }); 221 });
204 } 222 }
205 223
206 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 224 // If called for terrain has has not been previously allocated, a new terrain will be built
207 // based on the passed information. The 'id' should be either the terrain id or 225 // based on the passed information. The 'id' should be either the terrain id or
208 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 226 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
209 // The latter feature is for creating child terrains for mega-regions. 227 // The latter feature is for creating child terrains for mega-regions.
210 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 228 // If there is an existing terrain body, a new
211 // terrain shape is created and added to the body. 229 // 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. 230 // 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.) 231 // (The above does suggest that some simplification/refactoring is in order.)
232 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 233 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 234 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 235 {
217 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 236 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}",
218 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 237 BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime);
219 238
220 // Find high and low points of passed heightmap. 239 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 240 // 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 241 // 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. 242 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 243 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 244 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 245 foreach (float height in heightMap)
@@ -238,15 +257,15 @@ public sealed class BSTerrainManager
238 257
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 258 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 259
241 BSTerrainPhys terrainPhys; 260 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 261 {
244 // There is already a terrain in this spot. Free the old and build the new. 262 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 263 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 264 {
265 // There is already a terrain in this spot. Free the old and build the new.
266 DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
267 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
268
250 // Remove old terrain from the collection 269 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 270 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 271 // Release any physical memory it may be using.
@@ -254,6 +273,7 @@ public sealed class BSTerrainManager
254 273
255 if (MegaRegionParentPhysicsScene == null) 274 if (MegaRegionParentPhysicsScene == null)
256 { 275 {
276 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
257 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 277 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
258 m_terrains.Add(terrainRegionBase, newTerrainPhys); 278 m_terrains.Add(terrainRegionBase, newTerrainPhys);
259 279
@@ -271,35 +291,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 291 // I hate doing this, but just bail
272 return; 292 return;
273 } 293 }
274 }); 294 }
275 } 295 else
276 else 296 {
277 { 297 // 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 298 // 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 299
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 300 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 301 uint newTerrainID = id;
302 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
303 newTerrainID = ++m_terrainCount;
292 304
293 // Code that must happen at taint-time 305 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 306 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); 307 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 308 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 309
301 m_terrainModified = true; 310 m_terrainModified = true;
302 }); 311 }
303 } 312 }
304 } 313 }
305 314
@@ -308,9 +317,9 @@ public sealed class BSTerrainManager
308 { 317 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 318 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 319 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); 320 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
312 BSTerrainPhys newTerrainPhys = null; 321 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation) 322 switch ((int)BSParam.TerrainImplementation)
314 { 323 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 324 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 325 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@@ -323,14 +332,68 @@ public sealed class BSTerrainManager
323 default: 332 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 333 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader, 334 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation, 335 (int)BSParam.TerrainImplementation,
327 PhysicsScene.Params.terrainImplementation, 336 BSParam.TerrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase); 337 PhysicsScene.RegionName, terrainRegionBase);
329 break; 338 break;
330 } 339 }
331 return newTerrainPhys; 340 return newTerrainPhys;
332 } 341 }
333 342
343 // Return 'true' of this position is somewhere in known physical terrain space
344 public bool IsWithinKnownTerrain(Vector3 pos)
345 {
346 Vector3 terrainBaseXYZ;
347 BSTerrainPhys physTerrain;
348 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
349 }
350
351 // Return a new position that is over known terrain if the position is outside our terrain.
352 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
353 {
354 Vector3 ret = pPos;
355
356 // First, base addresses are never negative so correct for that possible problem.
357 if (ret.X < 0f || ret.Y < 0f)
358 {
359 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
360 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
361 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
362 BSScene.DetailLogZero, pPos, ret);
363 }
364
365 // Can't do this function if we don't know about any terrain.
366 if (m_terrains.Count == 0)
367 return ret;
368
369 int loopPrevention = 10;
370 Vector3 terrainBaseXYZ;
371 BSTerrainPhys physTerrain;
372 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
373 {
374 // The passed position is not within a known terrain area.
375 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
376
377 // Must be off the top of a region. Find an adjacent region to move into.
378 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
379
380 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
381 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
382 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
383 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
384
385 if (loopPrevention-- < 0f)
386 {
387 // The 'while' is a little dangerous so this prevents looping forever if the
388 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
389 // the list of terrains is in transition.
390 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
391 break;
392 }
393 }
394
395 return ret;
396 }
334 397
335 // Given an X and Y, find the height of the terrain. 398 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 399 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +404,125 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 404 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 405 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 406 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 407 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 408 {
346 float tX = loc.X; 409 float tX = pos.X;
347 float tY = loc.Y; 410 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 411 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 412 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 413 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 414 return lastHeight;
415 m_terrainModified = false;
352 416
353 lastHeightTX = tX; 417 lastHeightTX = tX;
354 lastHeightTY = tY; 418 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 419 float ret = HEIGHT_GETHEIGHT_RET;
356 420
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 421 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; 422 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 423 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 424 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 425 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 426 }
368 else 427 else
369 { 428 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 429 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 430 LogHeader, PhysicsScene.RegionName, tX, tY);
431 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
432 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 433 }
373 m_terrainModified = false; 434
374 lastHeight = ret; 435 lastHeight = ret;
375 return ret; 436 return ret;
376 } 437 }
377 438
439 public float GetWaterLevelAtXYZ(Vector3 pos)
440 {
441 float ret = WATER_HEIGHT_GETHEIGHT_RET;
442
443 Vector3 terrainBaseXYZ;
444 BSTerrainPhys physTerrain;
445 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
446 {
447 ret = physTerrain.GetWaterLevelAtXYZ(pos);
448 }
449 else
450 {
451 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
452 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
453 }
454 return ret;
455 }
456
457 // Given an address, return 'true' of there is a description of that terrain and output
458 // the descriptor class and the 'base' fo the addresses therein.
459 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
460 {
461 bool ret = false;
462
463 Vector3 terrainBaseXYZ = Vector3.Zero;
464 if (pos.X < 0f || pos.Y < 0f)
465 {
466 // We don't handle negative addresses so just make up a base that will not be found.
467 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
468 }
469 else
470 {
471 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
472 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
473 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
474 }
475
476 BSTerrainPhys physTerrain = null;
477 lock (m_terrains)
478 {
479 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
480 }
481 outTerrainBase = terrainBaseXYZ;
482 outPhysTerrain = physTerrain;
483 return ret;
484 }
485
486 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
487 // this one. Usually used to return an out of bounds object to a known place.
488 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
489 {
490 Vector3 ret = pTerrainBase;
491
492 // Can't do this function if we don't know about any terrain.
493 if (m_terrains.Count == 0)
494 return ret;
495
496 // Just some sanity
497 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
498 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
499 ret.Z = 0f;
500
501 lock (m_terrains)
502 {
503 // Once down to the <0,0> region, we have to be done.
504 while (ret.X > 0f || ret.Y > 0f)
505 {
506 if (ret.X > 0f)
507 {
508 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
509 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
510 if (m_terrains.ContainsKey(ret))
511 break;
512 }
513 if (ret.Y > 0f)
514 {
515 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
516 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
517 if (m_terrains.ContainsKey(ret))
518 break;
519 }
520 }
521 }
522
523 return ret;
524 }
525
378 // Although no one seems to check this, I do support combining. 526 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 527 public bool SupportsCombining()
380 { 528 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..2ce1513 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -76,27 +76,43 @@ public sealed class BSTerrainMesh : BSTerrainPhys
76 m_sizeX = (int)(maxCoords.X - minCoords.X); 76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y); 77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78 78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, 79 bool meshCreationSuccess = false;
80 m_sizeX, m_sizeY, 80 if (BSParam.TerrainMeshMagnification == 1)
81 (float)m_sizeX, (float)m_sizeY, 81 {
82 Vector3.Zero, 1.0f, 82 // If a magnification of one, use the old routine that is tried and true.
83 out indicesCount, out indices, out verticesCount, out vertices)) 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices);
87 }
88 else
89 {
90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize,
95 Vector3.Zero, // base for mesh
96 out indicesCount, out indices, out verticesCount, out vertices);
97 }
98 if (!meshCreationSuccess)
84 { 99 {
85 // DISASTER!! 100 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); 101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 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. 103 // Something is very messed up and a crash is in our future.
89 return; 104 return;
90 } 105 }
91 106
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
93 indicesCount, indices, verticesCount, vertices), 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
94 BSPhysicsShapeType.SHAPE_MESH); 109
95 if (m_terrainShape.ptr == IntPtr.Zero) 110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape)
96 { 112 {
97 // DISASTER!! 113 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
101 return; 117 return;
102 } 118 }
@@ -104,49 +120,58 @@ public sealed class BSTerrainMesh : BSTerrainPhys
104 Vector3 pos = regionBase; 120 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity; 121 Quaternion rot = Quaternion.Identity;
106 122
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 123 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (m_terrainBody.ptr == IntPtr.Zero) 124 if (!m_terrainBody.HasPhysicalBody)
109 { 125 {
110 // DISASTER!! 126 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 127 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
113 return; 129 return;
114 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
115 132
116 // Set current terrain attributes 133 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); 134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 139
122 // Static objects are not very massive. 140 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 141 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124 142
125 // Return the new terrain to the world of physical objects 143 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127 145
128 // redo its bounding box now that it is in the world 146 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 147 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130 148
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 149 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 150 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133 (uint)CollisionFilterGroups.TerrainMask); 151
152 if (BSParam.UseSingleSidedMeshes)
153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 }
134 157
135 // Make it so the terrain will not move or be considered for movement. 158 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 159 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
137 } 160 }
138 161
139 public override void Dispose() 162 public override void Dispose()
140 { 163 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 164 if (m_terrainBody.HasPhysicalBody)
142 { 165 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
144 // Frees both the body and the shape. 167 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); 168 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
169 m_terrainBody.Clear();
170 m_terrainShape.Clear();
146 } 171 }
147 } 172 }
148 173
149 public override float GetHeightAtXYZ(Vector3 pos) 174 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 175 {
151 // For the moment use the saved heightmap to get the terrain height. 176 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 177 // TODO: raycast downward to find the true terrain below the position.
@@ -167,14 +192,17 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 192 return ret;
168 } 193 }
169 194
195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 {
198 return PhysicsScene.SimpleWaterLevel;
199 }
200
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 202 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 203 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
173 BSScene physicsScene,
174 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap 204 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
175 float extentX, float extentY, // zero based range for output vertices
176 Vector3 extentBase, // base to be added to all vertices 205 Vector3 extentBase, // base to be added to all vertices
177 float magnification, // number of vertices to create between heightMap coords
178 out int indicesCountO, out int[] indicesO, 206 out int indicesCountO, out int[] indicesO,
179 out int verticesCountO, out float[] verticesO) 207 out int verticesCountO, out float[] verticesO)
180 { 208 {
@@ -188,43 +216,47 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 216 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 217 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 218
219 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
220 // from zero to <= sizeX). The triangle indices are then generated as two triangles
221 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
222 // column of vertices are used to complete the triangles of the last row and column
223 // of the heightmap.
191 try 224 try
192 { 225 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 226 // One vertice per heightmap value plus the vertices off the side and bottom edge.
194 int totalVertices = (sizeX + 1) * (sizeY + 1); 227 int totalVertices = (sizeX + 1) * (sizeY + 1);
195 vertices = new float[totalVertices * 3]; 228 vertices = new float[totalVertices * 3];
196 int totalIndices = sizeX * sizeY * 6; 229 int totalIndices = sizeX * sizeY * 6;
197 indices = new int[totalIndices]; 230 indices = new int[totalIndices];
198 231
199 float magX = (float)sizeX / extentX; 232 if (physicsScene != null)
200 float magY = (float)sizeY / extentY; 233 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 234 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 235 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 236 // 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++) 237 for (int yy = 0; yy <= sizeY; yy++)
205 { 238 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 239 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 240 {
208 int offset = yy * sizeX + xx; 241 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 242 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 243 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 244 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 245 float height = heightMap[offset];
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 246 minHeight = Math.Min(minHeight, height);
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 247 vertices[verticesCount + 0] = (float)xx + extentBase.X;
248 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 249 vertices[verticesCount + 2] = height + extentBase.Z;
216 verticesCount += 3; 250 verticesCount += 3;
217 } 251 }
218 } 252 }
219 verticesCount = verticesCount / 3; 253 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 254
223 for (int yy = 0; yy < sizeY; yy++) 255 for (int yy = 0; yy < sizeY; yy++)
224 { 256 {
225 for (int xx = 0; xx < sizeX; xx++) 257 for (int xx = 0; xx < sizeX; xx++)
226 { 258 {
227 int offset = yy * sizeX + xx; 259 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 260 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 261 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 262 indices[indicesCount + 1] = offset + 1;
@@ -235,13 +267,166 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 267 indicesCount += 6;
236 } 268 }
237 } 269 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 270
239 LogHeader, indicesCount); // DEBUG 271 ret = true;
272 }
273 catch (Exception e)
274 {
275 if (physicsScene != null)
276 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
277 LogHeader, physicsScene.RegionName, extentBase, e);
278 }
279
280 indicesCountO = indicesCount;
281 indicesO = indices;
282 verticesCountO = verticesCount;
283 verticesO = vertices;
284
285 return ret;
286 }
287
288 private class HeightMapGetter
289 {
290 private float[] m_heightMap;
291 private int m_sizeX;
292 private int m_sizeY;
293 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
294 {
295 m_heightMap = pHeightMap;
296 m_sizeX = pSizeX;
297 m_sizeY = pSizeY;
298 }
299 // The heightmap is extended as an infinite plane at the last height
300 public float GetHeight(int xx, int yy)
301 {
302 int offset = 0;
303 // Extend the height with the height from the last row or column
304 if (yy >= m_sizeY)
305 if (xx >= m_sizeX)
306 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
307 else
308 offset = (m_sizeY - 1) * m_sizeX + xx;
309 else
310 if (xx >= m_sizeX)
311 offset = yy * m_sizeX + (m_sizeX - 1);
312 else
313 offset = yy * m_sizeX + xx;
314
315 return m_heightMap[offset];
316 }
317 }
318
319 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
320 // Version that handles magnification.
321 // Return 'true' if successfully created.
322 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
323 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
324 int magnification, // number of vertices per heighmap step
325 Vector3 extent, // dimensions of the output mesh
326 Vector3 extentBase, // base to be added to all vertices
327 out int indicesCountO, out int[] indicesO,
328 out int verticesCountO, out float[] verticesO)
329 {
330 bool ret = false;
331
332 int indicesCount = 0;
333 int verticesCount = 0;
334 int[] indices = new int[0];
335 float[] vertices = new float[0];
336
337 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
338
339 // The vertices dimension of the output mesh
340 int meshX = sizeX * magnification;
341 int meshY = sizeY * magnification;
342 // The output size of one mesh step
343 float meshXStep = extent.X / meshX;
344 float meshYStep = extent.Y / meshY;
345
346 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
347 // from zero to <= meshX). The triangle indices are then generated as two triangles
348 // per heightmap point. There are meshX by meshY of these squares. The extra row and
349 // column of vertices are used to complete the triangles of the last row and column
350 // of the heightmap.
351 try
352 {
353 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
354 int totalVertices = (meshX + 1) * (meshY + 1);
355 vertices = new float[totalVertices * 3];
356 int totalIndices = meshX * meshY * 6;
357 indices = new int[totalIndices];
358
359 if (physicsScene != null)
360 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
361 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
362 totalVertices, totalIndices, extentBase);
363
364 float minHeight = float.MaxValue;
365 // Note that sizeX+1 vertices are created since there is land between this and the next region.
366 // Loop through the output vertices and compute the mediun height in between the input vertices
367 for (int yy = 0; yy <= meshY; yy++)
368 {
369 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
370 {
371 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
372 int stepY = (int)offsetY;
373 float fractionalY = offsetY - (float)stepY;
374 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
375 int stepX = (int)offsetX;
376 float fractionalX = offsetX - (float)stepX;
377
378 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
379 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
380
381 // get the four corners of the heightmap square the mesh point is in
382 float heightUL = hmap.GetHeight(stepX , stepY );
383 float heightUR = hmap.GetHeight(stepX + 1, stepY );
384 float heightLL = hmap.GetHeight(stepX , stepY + 1);
385 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
386
387 // bilinear interplolation
388 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
389 + heightUR * fractionalX * (1 - fractionalY)
390 + heightLL * (1 - fractionalX) * fractionalY
391 + heightLR * fractionalX * fractionalY;
392
393 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
394 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
395
396 minHeight = Math.Min(minHeight, height);
397
398 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
399 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
400 vertices[verticesCount + 2] = height + extentBase.Z;
401 verticesCount += 3;
402 }
403 }
404 // The number of vertices generated
405 verticesCount /= 3;
406
407 // Loop through all the heightmap squares and create indices for the two triangles for that square
408 for (int yy = 0; yy < meshY; yy++)
409 {
410 for (int xx = 0; xx < meshX; xx++)
411 {
412 int offset = yy * (meshX + 1) + xx;
413 // Each vertices is presumed to be the upper left corner of a box of two triangles
414 indices[indicesCount + 0] = offset;
415 indices[indicesCount + 1] = offset + 1;
416 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
417 indices[indicesCount + 3] = offset + 1;
418 indices[indicesCount + 4] = offset + meshX + 2;
419 indices[indicesCount + 5] = offset + meshX + 1;
420 indicesCount += 6;
421 }
422 }
423
240 ret = true; 424 ret = true;
241 } 425 }
242 catch (Exception e) 426 catch (Exception e)
243 { 427 {
244 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", 428 if (physicsScene != null)
429 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
245 LogHeader, physicsScene.RegionName, extentBase, e); 430 LogHeader, physicsScene.RegionName, extentBase, e);
246 } 431 }
247 432
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..8012d91
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,269 @@
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// An object's 'group' is the collison groups this object belongs to
221// An object's 'filter' is the groups another object has to belong to in order to collide with me
222// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
223//
224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
225// but, instead, use references to this dictionary. Finding and debugging
226// collision flag problems will be made easier.
227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
229{
230 { CollisionType.Avatar,
231 new CollisionTypeFilterGroup(CollisionType.Avatar,
232 (uint)CollisionFilterGroups.BCharacterGroup,
233 (uint)CollisionFilterGroups.BAllGroup)
234 },
235 { CollisionType.Groundplane,
236 new CollisionTypeFilterGroup(CollisionType.Groundplane,
237 (uint)CollisionFilterGroups.BGroundPlaneGroup,
238 (uint)CollisionFilterGroups.BAllGroup)
239 },
240 { CollisionType.Terrain,
241 new CollisionTypeFilterGroup(CollisionType.Terrain,
242 (uint)CollisionFilterGroups.BTerrainGroup,
243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
244 },
245 { CollisionType.Static,
246 new CollisionTypeFilterGroup(CollisionType.Static,
247 (uint)CollisionFilterGroups.BStaticGroup,
248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
249 },
250 { CollisionType.Dynamic,
251 new CollisionTypeFilterGroup(CollisionType.Dynamic,
252 (uint)CollisionFilterGroups.BSolidGroup,
253 (uint)(CollisionFilterGroups.BAllGroup))
254 },
255 { CollisionType.VolumeDetect,
256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
257 (uint)CollisionFilterGroups.BSensorTrigger,
258 (uint)(~CollisionFilterGroups.BSensorTrigger))
259 },
260 { CollisionType.LinksetChild,
261 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
262 (uint)CollisionFilterGroups.BLinksetChildGroup,
263 (uint)(CollisionFilterGroups.BNoneGroup))
264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
265 },
266};
267
268}
269}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..8a15abe
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,346 @@
1CURRENT PRIORITIES
2=================================================
3Use the HACD convex hull routine in Bullet rather than the C# version.
4 Speed up hullifying large meshes.
5Enable vehicle border crossings (at least as poorly as ODE)
6 Terrain skirts
7 Avatar created in previous region and not new region when crossing border
8 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
9Lock axis
10Deleting a linkset while standing on the root will leave the physical shape of the root behind.
11 Not sure if it is because standing on it. Done with large prim linksets.
12Linkset child rotations.
13 Nebadon spiral tube has middle sections which are rotated wrong.
14 Select linked spiral tube. Delink and note where the middle section ends up.
15Vehicle angular vertical attraction
16vehicle angular banking
17Center-of-gravity
18Vehicle angular deflection
19 Preferred orientation angular correction fix
20when should angular and linear motor targets be zeroed? when selected?
21 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
22Teravus llMoveToTarget script debug
23 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
24 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
25limitMotorUp calibration (more down?)
26llRotLookAt
27llLookAt
28Avatars walking up stairs (HALF DONE)
29Avatar movement
30 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
31 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
32 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
33Vehicle script tuning/debugging
34 Avanti speed script
35 Weapon shooter script
36Move material definitions (friction, ...) into simulator.
37Add material densities to the material types.
38Terrain detail: double terrain mesh detail
39One sided meshes? Should terrain be built into a closed shape?
40 When meshes get partially wedged into the terrain, they cannot push themselves out.
41 It is possible that Bullet processes collisions whether entering or leaving a mesh.
42 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
43
44VEHICLES TODO LIST:
45=================================================
46Border crossing with linked vehicle causes crash
47 20121129.1411: editting/moving phys object across region boundries causes crash
48 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
49Vehicles (Move smoothly)
50Some vehicles should not be able to turn if no speed or off ground.
51What to do if vehicle and prim buoyancy differ?
52Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
53Neb car jiggling left and right
54 Happens on terrain and any other mesh object. Flat cubes are much smoother.
55 This has been reduced but not eliminated.
56Implement referenceFrame for all the motion routines.
57For limitMotorUp, use raycast down to find if vehicle is in the air.
58Verify llGetVel() is returning a smooth and good value for vehicle movement.
59llGetVel() should return the root's velocity if requested in a child prim.
60Implement function efficiency for lineaar and angular motion.
61After getting off a vehicle, the root prim is phantom (can be walked through)
62 Need to force a position update for the root prim after compound shape destruction
63Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
64Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
65 A kludge that isn't fixing the real problem of Bullet adding extra motion.
66Incorporate inter-relationship of angular corrections. For instance, angularDeflection
67 and angularMotorUp will compute same X or Y correction. When added together
68 creates over-correction and over-shoot and wabbling.
69Vehicle attributes are not restored when a vehicle is rezzed on region creation
70 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
71
72GENERAL TODO LIST:
73=================================================
74Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
75 Regular triangle meshes don't do physical collisions.
76Resitution of a prim works on another prim but not on terrain.
77 The dropped prim doesn't bounce properly on the terrain.
78Add a sanity check for PIDTarget location.
79Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
80 Is much saved with lower LODs? At the moment, all set to 32.
81Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
82 If arrow show at prim, collision reported about 1/3 of time. If collision reported,
83 both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
84 Shooting 5m sphere "arrows" at 60m/s.
85llMoveToTarget objects are not effected by gravity until target is removed.
86Compute CCD parameters based on body size
87Can solver iterations be changed per body/shape? Can be for constraints but what
88 about regular vehicles?
89Implement llSetPhysicalMaterial.
90 extend it with Center-of-mass, rolling friction, density
91Implement llSetForceAndTorque.
92Change BSPrim.moveToTarget to used forces rather than changing position
93 Changing position allows one to move through walls
94Implement an avatar mesh shape. The Bullet capsule is way too limited.
95 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
96Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
97Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
98Duplicating a physical prim causes old prim to jump away
99 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
100Scenes with hundred of thousands of static objects take a lot of physics CPU time.
101BSPrim.Force should set a continious force on the prim. The force should be
102 applied each tick. Some limits?
103Gun sending shooter flying.
104Collision margin (gap between physical objects lying on each other)
105Boundry checking (crashes related to crossing boundry)
106 Add check for border edge position for avatars and objects.
107 Verify the events are created for border crossings.
108Avatar rotation (check out changes to ScenePresence for physical rotation)
109Avatar running (what does phys engine need to do?)
110Small physical objects do not interact correctly
111 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
112 The chain will fall apart and pairs will dance around on ground
113 Chains of 1x1x.2 will stay connected but will dance.
114 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
115Add PID motor for avatar movement (slow to stop, ...)
116setForce should set a constant force. Different than AddImpulse.
117Implement raycast.
118Implement ShapeCollection.Dispose()
119Implement water as a plain so raycasting and collisions can happen with same.
120Add collision penetration return
121 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
122Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
123 Also osGetPhysicsEngineVerion() maybe.
124Linkset.Position and Linkset.Orientation requre rewrite to properly return
125 child position. LinksetConstraint acts like it's at taint time!!
126Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
127Should the different PID factors have non-equal contributions for different
128 values of Efficiency?
129Selecting and deselecting physical objects causes CPU processing time to jump
130 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
131 put thousand physical objects, select and deselect same. CPU time will be large.
132Re-implement buoyancy as a separate force on the object rather than diddling gravity.
133 Register a pre-step event to add the force.
134More efficient memory usage when passing hull information from BSPrim to BulletSim
135Avatar movement motor check for zero or small movement. Somehow suppress small movements
136 when avatar has stopped and is just standing. Simple test for near zero has
137 the problem of preventing starting up (increase from zero) especially when falling.
138Physical and phantom will drop through the terrain
139
140
141LINKSETS
142======================================================
143Child prims do not report collisions
144Allow children of a linkset to be phantom:
145 http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
146 Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
147Editing a child of a linkset causes the child to go phantom
148 Move a child prim once when it is physical and can never move it again without it going phantom
149Offset the center of the linkset to be the geometric center of all the prims
150 Not quite the same as the center-of-gravity
151Linksets should allow collisions to individual children
152 Add LocalID to children shapes in LinksetCompound and create events for individuals
153LinksetCompound: when one of the children changes orientation (like tires
154 turning on a vehicle, the whole compound object is rebuilt. Optimize this
155 so orientation/position of individual children can change without a rebuild.
156Verify/think through scripts in children of linksets. What do they reference
157 and return when getting position, velocity, ...
158Confirm constraint linksets still work after making all the changes for compound linksets.
159Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
160Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
161 For compound linksets, add ability to remove or reposition individual child shapes.
162Speed up creation of large physical linksets
163 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
164 REALLY bad for very large physical linksets (freezes the sim for many seconds).
165Eliminate collisions between objects in a linkset. (LinksetConstraint)
166 Have UserPointer point to struct with localID and linksetID?
167 Objects in original linkset still collide with each other?
168
169MORE
170======================================================
171Create tests for different interface components
172 Have test objects/scripts measure themselves and turn color if correct/bad
173 Test functions in SL and calibrate correctness there
174 Create auto rezzer and tracker to run through the tests
175Do we need to do convex hulls all the time? Can complex meshes be left meshes?
176 There is some problem with meshes and collisions
177 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
178Debounce avatar contact so legs don't keep folding up when standing.
179Implement LSL physics controls. Like STATUS_ROTATE_X.
180Add border extensions to terrain to help region crossings and objects leaving region.
181Use a different capsule shape for avatar when sitting
182 LL uses a pyrimidal shape scaled by the avatar's bounding box
183 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
184Performance test with lots of avatars. Can BulletSim support a thousand?
185Optimize collisions in C++: only send up to the object subscribed to collisions.
186 Use collision subscription and remove the collsion(A,B) and collision(B,A)
187Check whether SimMotionState needs large if statement (see TODO).
188Implement 'top colliders' info.
189Avatar jump
190Performance measurement and changes to make quicker.
191Implement detailed physics stats (GetStats()).
192Measure performance improvement from hulls
193Test not using ghost objects for volume detect implementation.
194Performance of closures and delegates for taint processing
195 Are there faster ways?
196 Is any slowdown introduced by the existing implementation significant?
197Is there are more efficient method of implementing pre and post step actions?
198 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
199Physics Arena central pyramid: why is one side permiable?
200In SL, perfect spheres don't seem to have rolling friction. Add special case.
201Enforce physical parameter min/max:
202 Gravity: [-1, 28]
203 Friction: [0, 255]
204 Density: [1, 22587]
205 Restitution [0, 1]
206 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
207Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
208Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
209
210INTERNAL IMPROVEMENT/CLEANUP
211=================================================
212Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
213 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
214Create the physical wrapper classes (BulletBody, BulletShape) by methods on
215 BSAPITemplate and make their actual implementation Bullet engine specific.
216 For the short term, just call the existing functions in ShapeCollection.
217Consider moving prim/character body and shape destruction in destroy()
218 to postTimeTime rather than protecting all the potential sets that
219 might have been queued up.
220Remove unused fields from ShapeData (not used in API2)
221Remove unused fields from pinned memory shared parameter block
222 Create parameter variables in BSScene to replace same.
223Breakout code for mesh/hull/compound/native into separate BSShape* classes
224 Standardize access to building and reference code.
225 The skeleton classes are in the sources but are not complete or linked in.
226Make BSBody and BSShape real classes to centralize creation/changin/destruction
227 Convert state and parameter calls from BulletSimAPI direct calls to
228 calls on BSBody and BSShape
229Generalize Dynamics and PID with standardized motors.
230Generalize Linkset and vehicles into PropertyManagers
231 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
232 Potentially add events for shape destruction, etc.
233Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
234 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
235Implement linkset by setting position of children when root updated. (LinksetManual)
236 Linkset implementation using manual prim movement.
237LinkablePrim class? Would that simplify/centralize the linkset logic?
238BSScene.UpdateParameterSet() is broken. How to set params on objects?
239Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
240 bob at the water level. BSPrim.PositionSanityCheck()
241Should taints check for existance or activeness of target?
242 When destroying linksets/etc, taints can be generated for objects that are
243 actually gone when the taint happens. Crashes don't happen because the taint closure
244 keeps the object from being freed, but that is just an accident.
245 Possibly have an 'active' flag that is checked by the taint processor?
246Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
247Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
248There are TOO MANY interfaces from BulletSim core to Bullet itself
249 Think of something to eliminate one or more of the layers
250
251THREADING
252=================================================
253Do taint action immediately if not actually executing Bullet.
254 Add lock around Bullet execution and just do taint actions if simulation is not happening.
255
256DONE DONE DONE DONE
257=================================================
258Cleanup code in BSDynamics by using motors. (Resolution: started)
259Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
260 Would have better and adjustable resolution.
261Build terrain mesh so heighmap is height of the center of the square meter.
262 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
263Terrain as mesh. (Resolution: done)
264How are static linksets seen by the physics engine?
265 Resolution: they are not linked in physics. When moved, all the children are repositioned.
266Convert BSCharacter to use all API2 (Resolution: done)
267Avatar pushing difficult (too heavy?)
268Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
269Remove old code in DLL (all non-API2 stuff). (Resolution: done)
270Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
271Debug Bullet internal stats output (why is timing all wrong?)
272 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
273Implement meshes or just verify that they work. (Resolution: they do!)
274Do prim hash codes work for sculpties and meshes? (Resolution: yes)
275Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
276 Compound shapes will need the LocalID in the shapes and collision
277 processing to get it from there.
278Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
279Package Bullet source mods for Bullet internal stats output
280 (Resolution: move code into WorldData.h rather than relying on patches)
281Single prim vehicles don't seem to properly vehiclize.
282 (Resolution: mass was not getting set properly for single prim linksets)
283Add material type linkage and input all the material property definitions.
284 Skeleton classes and table are in the sources but are not filled or used.
285 (Resolution:
286Neb vehicle taking > 25ms of physics time!!
287 (Resolution: compound linksets were being rebuild WAY too often)
288Avatar height off after unsitting (floats off ground)
289 Editting appearance then moving restores.
290 Must not be initializing height when recreating capsule after unsit.
291 (Resolution: confusion of scale vs size for native objects removed)
292Light cycle falling over when driving (Resolution: implemented angularMotorUp)
293Should vehicle angular/linear movement friction happen after all the components
294 or does it only apply to the basic movement?
295 (Resolution: friction added before returning newly computed motor value.
296 What is expected by some vehicles (turning up friction to moderate speed))
297Tune terrain/object friction to be closer to SL.
298 (Resolution: added material type with friction and resolution)
299Smooth avatar movement with motor (DONE)
300 Should motor update be all at taint-time? (Yes, DONE)
301 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
302 (Resolution: added BSVMotor for avatar starting and stopping)
303llApplyImpulse()
304 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
305 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
306llSetBuoyancy() (DONE)
307 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
308Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
309 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
310Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
311 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
312Meshes rendering as bounding boxes (DONE)
313 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
314llMoveToTarget (Resolution: added simple motor to update the position.)
315Angular motor direction is global coordinates rather than local coordinates (DONE)
316Add vehicle collisions so IsColliding is properly reported. (DONE)
317 Needed for banking, limitMotorUp, movementLimiting, ...
318 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
319VehicleAddForce is not scaled by the simulation step but it is only
320 applied for one step. Should it be scaled? (DONE)
321 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
322Complete implemention of preStepActions (DONE)
323 Replace vehicle step call with prestep event.
324 Is there a need for postStepActions? postStepTaints?
325Disable activity of passive linkset children. (DONE)
326 Since the linkset is a compound object, the old prims are left lying
327 around and need to be phantomized so they don't collide, ...
328Remove HeightmapInfo from terrain specification (DONE)
329 Since C++ code does not need terrain height, this structure et al are not needed.
330Surfboard go wonky when turning (DONE)
331 Angular motor direction is global coordinates rather than local coordinates?
332 (Resolution: made angular motor direction correct coordinate system)
333Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
334 Msg Kayaker on OSGrid when working
335 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
336 same in SL as in OS/BulletSim)
337Boats float low in the water (DONE)
338Boats floating at proper level (DONE)
339When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
340 (Resolution: setForce registers a prestep action which keeps applying the force)
341Child movement in linkset (don't rebuild linkset) (DONE 20130122))
342Avatar standing on a moving object should start to move with the object. (DONE 20130125)
343Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
344 Verify that angular motion specified around Z moves in the vehicle coordinates.
345 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
346Nebadon vehicles turning funny in arena (DONE)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
index 0d1db3b..02b03a8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..33232bd
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.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 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.Tests
44{
45[TestFixture]
46public class BasicVehicles : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 BSPrim TestVehicle { get; set; }
53 Vector3 TestVehicleInitPosition { get; set; }
54 float simulationTimeStep = 0.089f;
55
56 [TestFixtureSetUp]
57 public void Init()
58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
61
62 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
63 Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
64 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
65 TestVehicleInitPosition = pos;
66 Vector3 size = new Vector3(1f, 1f, 1f);
67 pbs.Scale = size;
68 Quaternion rot = Quaternion.Identity;
69 bool isPhys = false;
70 uint localID = 123;
71
72 PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
73 TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
74 // The actual prim shape creation happens at taint time
75 PhysicsScene.ProcessTaints();
76
77 }
78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 if (PhysicsScene != null)
83 {
84 // The Dispose() will also free any physical objects in the scene
85 PhysicsScene.Dispose();
86 PhysicsScene = null;
87 }
88 }
89
90 [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
91 [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
92 [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
93 [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
94 // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
95 // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
96 // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
97 // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
98 // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
99 // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
100 // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
101 // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
102 public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
103 {
104 // Enough simulation steps to cover the timescale the operation should take
105 int simSteps = (int)(timeScale / simulationTimeStep) + 1;
106
107 // Tip the vehicle
108 Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
109 TestVehicle.Orientation = initOrientation;
110
111 TestVehicle.Position = TestVehicleInitPosition;
112
113 // The vehicle controller is not enabled directly (by setting a vehicle type).
114 // Instead the appropriate values are set and calls are made just the parts of the
115 // controller we want to exercise. Stepping the physics engine then applies
116 // the actions of that one feature.
117 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
118 TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
119 TestVehicle.VehicleController.enableAngularVerticalAttraction = true;
120
121 TestVehicle.IsPhysical = true;
122 PhysicsScene.ProcessTaints();
123
124 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
125 for (int ii = 0; ii < simSteps; ii++)
126 {
127 TestVehicle.VehicleController.ForgetKnownVehicleProperties();
128 TestVehicle.VehicleController.ComputeAngularVerticalAttraction();
129 TestVehicle.VehicleController.PushKnownChanged();
130
131 PhysicsScene.Simulate(simulationTimeStep);
132 }
133
134 TestVehicle.IsPhysical = false;
135 PhysicsScene.ProcessTaints();
136
137 // After these steps, the vehicle should be upright
138 /*
139 float finalRoll, finalPitch, finalYaw;
140 TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
141 Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
142 Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
143 Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
144 */
145
146 Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
147 Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
148 }
149}
150} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs
new file mode 100755
index 0000000..35cbc1d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTests.cs
@@ -0,0 +1,56 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Tests.Common;
37
38namespace OpenSim.Region.Physics.BulletSPlugin.Tests
39{
40[TestFixture]
41public class BulletSimTests : OpenSimTestCase
42{
43 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
44 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
45
46 [TestFixtureSetUp]
47 public void Init()
48 {
49 }
50
51 [TestFixtureTearDown]
52 public void TearDown()
53 {
54 }
55}
56}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs
new file mode 100755
index 0000000..28207a4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,95 @@
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.IO;
30using System.Collections.Generic;
31using System.Linq;
32using System.Text;
33
34using Nini.Config;
35
36using OpenSim.Framework;
37using OpenSim.Region.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Meshing;
39
40namespace OpenSim.Region.Physics.BulletSPlugin.Tests
41{
42// Utility functions for building up and tearing down the sample physics environments
43public static class BulletSimTestsUtil
44{
45 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
46 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
47 // May be 'null' if there are no overrides.
48 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
49 {
50 IConfigSource openSimINI = new IniConfigSource();
51 IConfig startupConfig = openSimINI.AddConfig("Startup");
52 startupConfig.Set("physics", "BulletSim");
53 startupConfig.Set("meshing", "Meshmerizer");
54 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
55
56 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
57 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
58 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
59 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
60 bulletSimConfig.Set("MeshSculptedPrim", "false");
61 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
62 if (paramOverrides != null)
63 {
64 foreach (KeyValuePair<string, string> kvp in paramOverrides)
65 {
66 bulletSimConfig.Set(kvp.Key, kvp.Value);
67 }
68 }
69
70 // If a special directory exists, put detailed logging therein.
71 // This allows local testing/debugging without having to worry that the build engine will output logs.
72 if (Directory.Exists("physlogs"))
73 {
74 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
75 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
76 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
77 bulletSimConfig.Set("VehicleLoggingEnabled","True");
78 }
79
80 BSPlugin bsPlugin = new BSPlugin();
81
82 BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion");
83
84 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
85 // In the future, add a fake asset fetcher to get meshes and sculpts.
86 // bsScene.RequestAssetMethod = ???;
87
88 Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI);
89 bsScene.Initialise(mesher, openSimINI);
90
91 return bsScene;
92 }
93
94}
95}
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/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
index 5ff945d..f611b9a 100644
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
32// You can specify all the values or you can default the Build and Revision Numbers 32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below: 33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")] 34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("0.7.5.*")] 35[assembly: AssemblyVersion("0.7.6.*")]
36[assembly: AssemblyFileVersion("1.0.0.0")] 36
diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
index 36b4235..5da3956 100644
--- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index ecc2918..5485eb7 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();
@@ -83,6 +83,7 @@ namespace OpenSim.Region.Physics.Manager
83 List<Vector3> getVertexList(); 83 List<Vector3> getVertexList();
84 int[] getIndexListAsInt(); 84 int[] getIndexListAsInt();
85 int[] getIndexListAsIntLocked(); 85 int[] getIndexListAsIntLocked();
86 float[] getVertexListAsFloat();
86 float[] getVertexListAsFloatLocked(); 87 float[] getVertexListAsFloatLocked();
87 void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); 88 void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount);
88 void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount); 89 void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount);
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
index b8676ba..31a397c 100755
--- a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
+++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
@@ -60,14 +60,14 @@ namespace OpenSim.Region.Physics.Manager
60 60
61 // Set parameter on a specific or all instances. 61 // Set parameter on a specific or all instances.
62 // Return 'false' if not able to set the parameter. 62 // Return 'false' if not able to set the parameter.
63 bool SetPhysicsParameter(string parm, float value, uint localID); 63 bool SetPhysicsParameter(string parm, string value, uint localID);
64 64
65 // Get parameter. 65 // Get parameter.
66 // Return 'false' if not able to get the parameter. 66 // Return 'false' if not able to get the parameter.
67 bool GetPhysicsParameter(string parm, out float value); 67 bool GetPhysicsParameter(string parm, out string value);
68 68
69 // Get parameter from a particular object 69 // Get parameter from a particular object
70 // TODO: 70 // TODO:
71 // bool GetPhysicsParameter(string parm, out float value, uint localID); 71 // bool GetPhysicsParameter(string parm, out string value, uint localID);
72 } 72 }
73} 73}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 9338130..7cd364b 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -274,7 +274,7 @@ namespace OpenSim.Region.Physics.Manager
274 public virtual float Density { get; set; } 274 public virtual float Density { get; set; }
275 public virtual float GravModifier { get; set; } 275 public virtual float GravModifier { get; set; }
276 public virtual float Friction { get; set; } 276 public virtual float Friction { get; set; }
277 public virtual float Bounce { get; set; } 277 public virtual float Restitution { get; set; }
278 278
279 /// <summary> 279 /// <summary>
280 /// Position of this actor. 280 /// Position of this actor.
@@ -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 57e2d20..20a70b4 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Region.Physics.Manager
47 public delegate void JointDeactivated(PhysicsJoint joint); 47 public delegate void JointDeactivated(PhysicsJoint joint);
48 public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" 48 public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
49 49
50 public enum RayFilterFlags:ushort 50 public enum RayFilterFlags : ushort
51 { 51 {
52 // the flags 52 // the flags
53 water = 0x01, 53 water = 0x01,
@@ -64,7 +64,7 @@ namespace OpenSim.Region.Physics.Manager
64 ClosestHit = 0x8000, 64 ClosestHit = 0x8000,
65 65
66 // some combinations 66 // some combinations
67 LSLPhanton = phantom | volumedtc, 67 LSLPhantom = phantom | volumedtc,
68 PrimsNonPhantom = nonphysical | physical, 68 PrimsNonPhantom = nonphysical | physical,
69 PrimsNonPhantomAgents = nonphysical | physical | agent, 69 PrimsNonPhantomAgents = nonphysical | physical | agent,
70 70
@@ -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/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs
index 6970553..e6b32e7 100644
--- a/OpenSim/Region/Physics/Meshing/Mesh.cs
+++ b/OpenSim/Region/Physics/Meshing/Mesh.cs
@@ -226,7 +226,7 @@ namespace OpenSim.Region.Physics.Meshing
226 return result; 226 return result;
227 } 227 }
228 228
229 private float[] getVertexListAsFloat() 229 public float[] getVertexListAsFloat()
230 { 230 {
231 if (m_vertices == null) 231 if (m_vertices == null)
232 throw new NotSupportedException(); 232 throw new NotSupportedException();
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/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
index 4cc1731..3de061a 100644
--- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
index 3c4f06a..f477ed1 100644
--- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
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..6d7f079 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;
@@ -4095,8 +4096,8 @@ namespace OpenSim.Region.Physics.OdePlugin
4095 lock (_prims) 4096 lock (_prims)
4096 { 4097 {
4097 List<OdePrim> orderedPrims = new List<OdePrim>(_prims); 4098 List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
4098 orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25); 4099 orderedPrims.OrderByDescending(p => p.CollisionScore);
4099 topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore); 4100 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
4100 4101
4101 foreach (OdePrim p in _prims) 4102 foreach (OdePrim p in _prims)
4102 p.CollisionScore = 0; 4103 p.CollisionScore = 0;
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/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
index d07df02..4289863 100644
--- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
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/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
index b67422f..fa06926 100644
--- a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
+++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Physics.Meshing
301 return result; 301 return result;
302 } 302 }
303 303
304 private float[] getVertexListAsFloat() 304 public float[] getVertexListAsFloat()
305 { 305 {
306 if (m_bdata.m_vertices == null) 306 if (m_bdata.m_vertices == null)
307 throw new NotSupportedException(); 307 throw new NotSupportedException();
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/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
index f7e4c1c..bea34d4 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
@@ -1014,8 +1014,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1014 offset.Y += contact.pos.Y; 1014 offset.Y += contact.pos.Y;
1015 offset.Z += contact.pos.Z; 1015 offset.Z += contact.pos.Z;
1016 1016
1017 _position = offset; 1017 //_position = offset;
1018 return false; 1018 //return false;
1019 } 1019 }
1020 1020
1021 offset.X = contact.pos.X - _position.X; 1021 offset.X = contact.pos.X - _position.X;
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/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs
index 4f598ea..2923ccf 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs
@@ -300,9 +300,9 @@ namespace OpenSim.Region.Physics.OdePlugin
300 ((ProbeSphereCallback)req.callbackMethod)(cresult); 300 ((ProbeSphereCallback)req.callbackMethod)(cresult);
301 } 301 }
302 302
303 private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; 303 private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhantom;
304// private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; 304// private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
305 private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; 305 private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhantom;
306 306
307 private void doSpaceRay(ODERayRequest req) 307 private void doSpaceRay(ODERayRequest req)
308 { 308 {
@@ -680,4 +680,4 @@ namespace OpenSim.Region.Physics.OdePlugin
680 public RayFilterFlags filter; 680 public RayFilterFlags filter;
681 public Quaternion orientation; 681 public Quaternion orientation;
682 } 682 }
683} \ No newline at end of file 683}
diff --git a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs
index 085eb59..86a3101 100644
--- a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
index a133e51..b4abc1d 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
@@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel
68 RootRegionLandChannel.Clear(setupDefaultParcel); 68 RootRegionLandChannel.Clear(setupDefaultParcel);
69 } 69 }
70 70
71 public ILandObject GetLandObject(Vector3 position)
72 {
73 return GetLandObject(position.X, position.Y);
74 }
75
71 public ILandObject GetLandObject(int x, int y) 76 public ILandObject GetLandObject(int x, int y)
72 { 77 {
73 //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); 78 //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 905540d..7127c73 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -415,18 +415,17 @@ namespace OpenSim.Region.RegionCombinerModule
415 */ 415 */
416 #endregion 416 #endregion
417 417
418 // If we're one region over +x y 418 // If we're one region over +x y (i.e. root region is to the west)
419 //xxx 419 //xxx
420 //xxy 420 //xxy
421 //xxx 421 //xxx
422
423 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) 422 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY)
424 { 423 {
425 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); 424 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
426 break; 425 break;
427 } 426 }
428 427
429 // If we're one region over x +y 428 // If we're one region over x +y (i.e. root region is to the south)
430 //xyx 429 //xyx
431 //xxx 430 //xxx
432 //xxx 431 //xxx
@@ -436,7 +435,7 @@ namespace OpenSim.Region.RegionCombinerModule
436 break; 435 break;
437 } 436 }
438 437
439 // If we're one region over +x +y 438 // If we're one region over +x +y (i.e. root region is to the south-west)
440 //xxy 439 //xxy
441 //xxx 440 //xxx
442 //xxx 441 //xxx
@@ -646,7 +645,6 @@ namespace OpenSim.Region.RegionCombinerModule
646 { 645 {
647 if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) 646 if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
648 { 647 {
649
650 rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; 648 rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
651 649
652 lock (rootConn.RegionScene.NorthBorders) 650 lock (rootConn.RegionScene.NorthBorders)
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs
index 2027ca6..30e99b0 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, WaitHandle coopSleepHandle);
47 } 50 }
48} \ No newline at end of file 51} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs
index 17c2708..b8fdd01 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs
@@ -25,16 +25,17 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using log4net;
29using System; 28using System;
30using OpenSim.Region.ScriptEngine.Shared; 29using System.Reflection;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes; 31using OpenSim.Region.Framework.Scenes;
32using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
33using OpenMetaverse;
34using Nini.Config;
35using OpenSim.Region.ScriptEngine.Interfaces; 33using OpenSim.Region.ScriptEngine.Interfaces;
34using OpenSim.Region.ScriptEngine.Shared;
36using Amib.Threading; 35using Amib.Threading;
37using OpenSim.Framework; 36using log4net;
37using Nini.Config;
38using OpenMetaverse;
38 39
39namespace OpenSim.Region.ScriptEngine.Interfaces 40namespace OpenSim.Region.ScriptEngine.Interfaces
40{ 41{
@@ -76,6 +77,38 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
76 IConfigSource ConfigSource { get; } 77 IConfigSource ConfigSource { get; }
77 string ScriptEngineName { get; } 78 string ScriptEngineName { get; }
78 string ScriptEnginePath { get; } 79 string ScriptEnginePath { get; }
80
81 /// <summary>
82 /// Return the name of the class that will be used for all running scripts.
83 /// </summary>
84 /// <remarks>
85 /// Each class goes in its own assembly so we don't need to otherwise distinguish the class name.
86 /// </remarks>
87 string ScriptClassName { get; }
88
89 /// <summary>
90 /// Return the name of the base class that will be used for all running scripts.
91 /// </summary>
92 string ScriptBaseClassName { get; }
93
94 /// <summary>
95 /// Assemblies that need to be referenced when compiling scripts.
96 /// </summary>
97 /// <remarks>
98 /// These are currently additional to those always referenced by the compiler, BUT THIS MAY CHANGE IN THE
99 /// FUTURE.
100 /// This can be null if there are no additional assemblies.
101 /// </remarks>
102 string[] ScriptReferencedAssemblies { get; }
103
104 /// <summary>
105 /// Parameters for the generated script's constructor.
106 /// </summary>
107 /// <remarks>
108 /// Can be null if there are no parameters
109 /// </remarks>
110 ParameterInfo[] ScriptBaseClassParameters { get; }
111
79 IScriptApi GetApi(UUID itemID, string name); 112 IScriptApi GetApi(UUID itemID, string name);
80 } 113 }
81} 114}
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index b04f6b6..35ae44c 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
@@ -50,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
50 { 52 {
51 bool Cancel(); 53 bool Cancel();
52 void Abort(); 54 void Abort();
53 bool Wait(TimeSpan t); 55
56 /// <summary>
57 /// Wait for the work item to complete.
58 /// </summary>
59 /// <param name='t'>The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite).</param>
60 bool Wait(int t);
54 } 61 }
55 62
56 /// <summary> 63 /// <summary>
@@ -59,6 +66,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
59 public interface IScriptInstance 66 public interface IScriptInstance
60 { 67 {
61 /// <summary> 68 /// <summary>
69 /// Debug level for this script instance.
70 /// </summary>
71 /// <remarks>
72 /// Level == 0, no extra data is logged.
73 /// Level >= 1, state changes are logged.
74 /// Level >= 2, event firing is logged.
75 /// <value>
76 /// The debug level.
77 /// </value>
78 int DebugLevel { get; set; }
79
80 /// <summary>
62 /// Is the script currently running? 81 /// Is the script currently running?
63 /// </summary> 82 /// </summary>
64 bool Running { get; set; } 83 bool Running { get; set; }
@@ -93,6 +112,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
93 /// </summary> 112 /// </summary>
94 long MeasurementPeriodExecutionTime { get; } 113 long MeasurementPeriodExecutionTime { get; }
95 114
115 /// <summary>
116 /// Scene part in which this script instance is contained.
117 /// </summary>
118 SceneObjectPart Part { get; }
119
96 IScriptEngine Engine { get; } 120 IScriptEngine Engine { get; }
97 UUID AppDomain { get; set; } 121 UUID AppDomain { get; set; }
98 string PrimName { get; } 122 string PrimName { get; }
@@ -112,8 +136,24 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
112 136
113 uint LocalID { get; } 137 uint LocalID { get; }
114 UUID AssetID { get; } 138 UUID AssetID { get; }
139
140 /// <summary>
141 /// Inventory item containing the script used.
142 /// </summary>
143 TaskInventoryItem ScriptTask { get; }
144
115 Queue EventQueue { get; } 145 Queue EventQueue { get; }
116 146
147 /// <summary>
148 /// Number of events queued for processing.
149 /// </summary>
150 long EventsQueued { get; }
151
152 /// <summary>
153 /// Number of events processed by this script instance.
154 /// </summary>
155 long EventsProcessed { get; }
156
117 void ClearQueue(); 157 void ClearQueue();
118 int StartParam { get; set; } 158 int StartParam { get; set; }
119 159
@@ -125,7 +165,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
125 /// <summary> 165 /// <summary>
126 /// Stop the script instance. 166 /// Stop the script instance.
127 /// </summary> 167 /// </summary>
168 /// <remarks>
169 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
170 /// there is a danger that it will self-abort and not complete the reset.
171 /// </remarks>
128 /// <param name="timeout"></param> 172 /// <param name="timeout"></param>
173 /// How many milliseconds we will wait for an existing script event to finish before
174 /// forcibly aborting that event.
129 /// <returns>true if the script was successfully stopped, false otherwise</returns> 175 /// <returns>true if the script was successfully stopped, false otherwise</returns>
130 bool Stop(int timeout); 176 bool Stop(int timeout);
131 177
@@ -147,8 +193,31 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
147 object EventProcessor(); 193 object EventProcessor();
148 194
149 int EventTime(); 195 int EventTime();
150 void ResetScript(); 196
197 /// <summary>
198 /// Reset the script.
199 /// </summary>
200 /// <remarks>
201 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
202 /// there is a danger that it will self-abort and not complete the reset. Such a thread must call
203 /// ApiResetScript() instead.
204 /// </remarks>
205 /// <param name='timeout'>
206 /// How many milliseconds we will wait for an existing script event to finish before
207 /// forcibly aborting that event prior to script reset.
208 /// </param>
209 void ResetScript(int timeout);
210
211 /// <summary>
212 /// Reset the script.
213 /// </summary>
214 /// <remarks>
215 /// This must not be called by any thread other than the one executing the scripts current event. This is
216 /// because there is no wait or abort logic if another thread is in the middle of processing a script event.
217 /// Such an external thread should use ResetScript() instead.
218 /// </remarks>
151 void ApiResetScript(); 219 void ApiResetScript();
220
152 Dictionary<string, object> GetVars(); 221 Dictionary<string, object> GetVars();
153 void SetVars(Dictionary<string, object> vars); 222 void SetVars(Dictionary<string, object> vars);
154 DetectParams GetDetectParams(int idx); 223 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..fce8ff8 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, WaitHandle 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 53c6e5c..bc35272 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -48,6 +48,7 @@ using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Framework.Scenes.Serialization; 49using OpenSim.Region.Framework.Scenes.Serialization;
50using OpenSim.Region.Framework.Scenes.Animation; 50using OpenSim.Region.Framework.Scenes.Animation;
51using OpenSim.Region.Framework.Scenes.Scripting;
51using OpenSim.Region.Physics.Manager; 52using OpenSim.Region.Physics.Manager;
52using OpenSim.Region.ScriptEngine.Shared; 53using OpenSim.Region.ScriptEngine.Shared;
53using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 54using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
@@ -70,6 +71,8 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
70using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; 71using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
71using System.Reflection; 72using System.Reflection;
72using Timer = System.Timers.Timer; 73using Timer = System.Timers.Timer;
74using System.Linq;
75using PermissionMask = OpenSim.Framework.PermissionMask;
73 76
74namespace OpenSim.Region.ScriptEngine.Shared.Api 77namespace OpenSim.Region.ScriptEngine.Shared.Api
75{ 78{
@@ -87,10 +90,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
87 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi 90 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
88 { 91 {
89 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 92 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
93
90 protected IScriptEngine m_ScriptEngine; 94 protected IScriptEngine m_ScriptEngine;
91 protected SceneObjectPart m_host; 95 protected SceneObjectPart m_host;
92 96
93 /// <summary> 97 /// <summary>
98 /// Used for script sleeps when we are using co-operative script termination.
99 /// </summary>
100 /// <remarks>null if co-operative script termination is not active</remarks>
101 WaitHandle m_coopSleepHandle;
102
103 /// <summary>
94 /// The item that hosts this script 104 /// The item that hosts this script
95 /// </summary> 105 /// </summary>
96 protected TaskInventoryItem m_item; 106 protected TaskInventoryItem m_item;
@@ -100,6 +110,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
100 protected float m_ScriptDelayFactor = 1.0f; 110 protected float m_ScriptDelayFactor = 1.0f;
101 protected float m_ScriptDistanceFactor = 1.0f; 111 protected float m_ScriptDistanceFactor = 1.0f;
102 protected float m_MinTimerInterval = 0.5f; 112 protected float m_MinTimerInterval = 0.5f;
113 protected float m_recoilScaleFactor = 0.0f;
103 114
104 protected DateTime m_timer = DateTime.Now; 115 protected DateTime m_timer = DateTime.Now;
105 protected bool m_waitingForScriptAnswer = false; 116 protected bool m_waitingForScriptAnswer = false;
@@ -140,34 +151,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
140 {"TURNLEFT", "Turning Left"}, 151 {"TURNLEFT", "Turning Left"},
141 {"TURNRIGHT", "Turning Right"} 152 {"TURNRIGHT", "Turning Right"}
142 }; 153 };
154 //An array of HTTP/1.1 headers that are not allowed to be used
155 //as custom headers by llHTTPRequest.
156 private string[] HttpStandardHeaders =
157 {
158 "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
159 "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
160 "Connection", "Content-Encoding", "Content-Language",
161 "Content-Length", "Content-Location", "Content-MD5",
162 "Content-Range", "Content-Type", "Date", "ETag", "Expect",
163 "Expires", "From", "Host", "If-Match", "If-Modified-Since",
164 "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
165 "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
166 "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
167 "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
168 "Vary", "Via", "Warning", "WWW-Authenticate"
169 };
143 170
144 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 171 public void Initialize(
172 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
145 { 173 {
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; 174 m_lastSayShoutCheck = DateTime.UtcNow;
153 175
154 m_ScriptEngine = ScriptEngine; 176 m_ScriptEngine = scriptEngine;
155 m_host = host; 177 m_host = host;
156 m_item = item; 178 m_item = item;
157 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); 179 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
180 m_coopSleepHandle = coopSleepHandle;
158 181
159 LoadLimits(); // read script limits from config. 182 LoadConfig();
160 183
161 m_TransferModule = 184 m_TransferModule =
162 m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); 185 m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
163 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>(); 186 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
164 m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>(); 187 m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
165 188
166 AsyncCommands = new AsyncCommandManager(ScriptEngine); 189 AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
167 } 190 }
168 191
169 /* load configuration items that affect script, object and run-time behavior. */ 192 /// <summary>
170 private void LoadLimits() 193 /// Load configuration items that affect script, object and run-time behavior. */
194 /// </summary>
195 private void LoadConfig()
171 { 196 {
172 m_ScriptDelayFactor = 197 m_ScriptDelayFactor =
173 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); 198 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
@@ -181,12 +206,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
181 m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); 206 m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255);
182 if (m_notecardLineReadCharsMax > 65535) 207 if (m_notecardLineReadCharsMax > 65535)
183 m_notecardLineReadCharsMax = 65535; 208 m_notecardLineReadCharsMax = 65535;
209
184 // load limits for particular subsystems. 210 // load limits for particular subsystems.
185 IConfig SMTPConfig; 211 IConfig SMTPConfig;
186 if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { 212 if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) {
187 // there's an smtp config, so load in the snooze time. 213 // there's an smtp config, so load in the snooze time.
188 EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); 214 EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
189 } 215 }
216
217 // Rezzing an object with a velocity can create recoil. This feature seems to have been
218 // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
219 // it by this factor. May be zero to turn off recoil all together.
220 m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
190 } 221 }
191 222
192 public override Object InitializeLifetimeService() 223 public override Object InitializeLifetimeService()
@@ -207,7 +238,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
207 delay = (int)((float)delay * m_ScriptDelayFactor); 238 delay = (int)((float)delay * m_ScriptDelayFactor);
208 if (delay == 0) 239 if (delay == 0)
209 return; 240 return;
210 System.Threading.Thread.Sleep(delay); 241
242 Sleep(delay);
243 }
244
245 protected virtual void Sleep(int delay)
246 {
247 if (m_coopSleepHandle == null)
248 System.Threading.Thread.Sleep(delay);
249 else
250 CheckForCoopTermination(delay);
251 }
252
253 /// <summary>
254 /// Check for co-operative termination.
255 /// </summary>
256 /// <param name='delay'>If called with 0, then just the check is performed with no wait.</param>
257 protected virtual void CheckForCoopTermination(int delay)
258 {
259 if (m_coopSleepHandle.WaitOne(delay))
260 throw new ScriptCoopStopException();
211 } 261 }
212 262
213 public Scene World 263 public Scene World
@@ -339,6 +389,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
339 } 389 }
340 } 390 }
341 391
392 /// <summary>
393 /// Get a given link entity from a linkset (linked objects and any sitting avatars).
394 /// </summary>
395 /// <remarks>
396 /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
397 /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
398 /// The ScenePresences receive linknums in the order in which they sat.
399 /// </remarks>
400 /// <returns>
401 /// The link entity. null if not found.
402 /// </returns>
403 /// <param name='linknum'>
404 /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
405 /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
406 /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
407 /// positive integer is given in this case then null is returned.
408 /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
409 /// of entities, then the entity which corresponds to that linknum is returned.
410 /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
411 /// null is returned.
412 /// </param>
413 public ISceneEntity GetLinkEntity(int linknum)
414 {
415 if (linknum < 0)
416 {
417 if (linknum == ScriptBaseClass.LINK_THIS)
418 return m_host;
419 else
420 return null;
421 }
422
423 int actualPrimCount = m_host.ParentGroup.PrimCount;
424 List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
425 int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
426
427 // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
428 // prim that has any avatars sat upon it (in which case the root prim is link 1).
429 if (linknum == 0)
430 {
431 if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
432 return m_host;
433
434 return null;
435 }
436 // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
437 // here we must match 1 (ScriptBaseClass.LINK_ROOT).
438 else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
439 {
440 if (sittingAvatarIds.Count > 0)
441 return m_host.ParentGroup.RootPart;
442 else
443 return null;
444 }
445 else if (linknum <= adjustedPrimCount)
446 {
447 if (linknum <= actualPrimCount)
448 {
449 return m_host.ParentGroup.GetLinkNumPart(linknum);
450 }
451 else
452 {
453 ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
454 if (sp != null)
455 return sp;
456 else
457 return null;
458 }
459 }
460 else
461 {
462 return null;
463 }
464 }
465
342 public List<SceneObjectPart> GetLinkParts(int linkType) 466 public List<SceneObjectPart> GetLinkParts(int linkType)
343 { 467 {
344 return GetLinkParts(m_host, linkType); 468 return GetLinkParts(m_host, linkType);
@@ -392,79 +516,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
392 } 516 }
393 } 517 }
394 518
395 protected UUID InventoryKey(string name, int type)
396 {
397 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
398
399 if (item != null && item.Type == type)
400 return item.AssetID;
401 else
402 return UUID.Zero;
403 }
404
405 /// <summary>
406 /// accepts a valid UUID, -or- a name of an inventory item.
407 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
408 /// in prim inventory.
409 /// </summary>
410 /// <param name="k"></param>
411 /// <returns></returns>
412 protected UUID KeyOrName(string k)
413 {
414 UUID key;
415
416 // if we can parse the string as a key, use it.
417 // else try to locate the name in inventory of object. found returns key,
418 // not found returns UUID.Zero
419 if (!UUID.TryParse(k, out key))
420 {
421 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k);
422
423 if (item != null)
424 key = item.AssetID;
425 else
426 key = UUID.Zero;
427 }
428
429 return key;
430 }
431
432 /// <summary>
433 /// Return the UUID of the asset matching the specified key or name
434 /// and asset type.
435 /// </summary>
436 /// <param name="k"></param>
437 /// <param name="type"></param>
438 /// <returns></returns>
439 protected UUID KeyOrName(string k, AssetType type)
440 {
441 UUID key;
442
443 if (!UUID.TryParse(k, out key))
444 {
445 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k);
446 if (item != null && item.Type == (int)type)
447 key = item.AssetID;
448 }
449 else
450 {
451 lock (m_host.TaskInventory)
452 {
453 foreach (KeyValuePair<UUID, TaskInventoryItem> item in m_host.TaskInventory)
454 {
455 if (item.Value.Type == (int)type && item.Value.Name == k)
456 {
457 key = item.Value.ItemID;
458 break;
459 }
460 }
461 }
462 }
463
464
465 return key;
466 }
467
468 //These are the implementations of the various ll-functions used by the LSL scripts. 519 //These are the implementations of the various ll-functions used by the LSL scripts.
469 public LSL_Float llSin(double f) 520 public LSL_Float llSin(double f)
470 { 521 {
@@ -1483,19 +1534,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1483 return 0; 1534 return 0;
1484 1535
1485 case ScriptBaseClass.STATUS_ROTATE_X: 1536 case ScriptBaseClass.STATUS_ROTATE_X:
1486 if (m_host.GetAxisRotation(2) == 2) 1537 // if (m_host.GetAxisRotation(2) != 0)
1538 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
1487 return 1; 1539 return 1;
1488 else 1540 else
1489 return 0; 1541 return 0;
1490 1542
1491 case ScriptBaseClass.STATUS_ROTATE_Y: 1543 case ScriptBaseClass.STATUS_ROTATE_Y:
1492 if (m_host.GetAxisRotation(4) == 4) 1544 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
1493 return 1; 1545 return 1;
1494 else 1546 else
1495 return 0; 1547 return 0;
1496 1548
1497 case ScriptBaseClass.STATUS_ROTATE_Z: 1549 case ScriptBaseClass.STATUS_ROTATE_Z:
1498 if (m_host.GetAxisRotation(8) == 8) 1550 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
1499 return 1; 1551 return 1;
1500 else 1552 else
1501 return 0; 1553 return 0;
@@ -1715,7 +1767,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1715 if (tex.FaceTextures[i] != null) 1767 if (tex.FaceTextures[i] != null)
1716 { 1768 {
1717 tex.FaceTextures[i].Shiny = sval; 1769 tex.FaceTextures[i].Shiny = sval;
1718 tex.FaceTextures[i].Bump = bump;; 1770 tex.FaceTextures[i].Bump = bump;
1719 } 1771 }
1720 tex.DefaultTexture.Shiny = sval; 1772 tex.DefaultTexture.Shiny = sval;
1721 tex.DefaultTexture.Bump = bump; 1773 tex.DefaultTexture.Bump = bump;
@@ -1838,7 +1890,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1838 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); 1890 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1839 tex.DefaultTexture.RGBA = texcolor; 1891 tex.DefaultTexture.RGBA = texcolor;
1840 } 1892 }
1841 1893
1842 part.UpdateTextureEntry(tex.GetBytes()); 1894 part.UpdateTextureEntry(tex.GetBytes());
1843 return; 1895 return;
1844 } 1896 }
@@ -1875,10 +1927,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1875 part.Shape.FlexiForceX = (float)Force.x; 1927 part.Shape.FlexiForceX = (float)Force.x;
1876 part.Shape.FlexiForceY = (float)Force.y; 1928 part.Shape.FlexiForceY = (float)Force.y;
1877 part.Shape.FlexiForceZ = (float)Force.z; 1929 part.Shape.FlexiForceZ = (float)Force.z;
1878 part.Shape.PathCurve = 0x80; 1930 part.Shape.PathCurve = (byte)Extrusion.Flexible;
1879 part.ParentGroup.HasGroupChanged = true;
1880 part.ScheduleFullUpdate();
1881 } 1931 }
1932 else
1933 {
1934 // Other values not set, they do not seem to be sent to the viewer
1935 // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
1936 part.Shape.PathCurve = (byte)Extrusion.Straight;
1937 part.Shape.FlexiEntry = false;
1938 }
1939 part.ParentGroup.HasGroupChanged = true;
1940 part.ScheduleFullUpdate();
1882 } 1941 }
1883 1942
1884 /// <summary> 1943 /// <summary>
@@ -1954,7 +2013,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1954 rgb.x = texcolor.R; 2013 rgb.x = texcolor.R;
1955 rgb.y = texcolor.G; 2014 rgb.y = texcolor.G;
1956 rgb.z = texcolor.B; 2015 rgb.z = texcolor.B;
1957 2016
1958 return rgb; 2017 return rgb;
1959 } 2018 }
1960 else 2019 else
@@ -1996,12 +2055,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1996 2055
1997 UUID textureID = new UUID(); 2056 UUID textureID = new UUID();
1998 2057
1999 textureID = InventoryKey(texture, (int)AssetType.Texture); 2058 textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
2000 if (textureID == UUID.Zero) 2059 if (textureID == UUID.Zero)
2001 { 2060 {
2002 if (!UUID.TryParse(texture, out textureID)) 2061 if (!UUID.TryParse(texture, out textureID))
2003 return; 2062 return;
2004 } 2063 }
2005 2064
2006 Primitive.TextureEntry tex = part.Shape.Textures; 2065 Primitive.TextureEntry tex = part.Shape.Textures;
2007 2066
@@ -2207,7 +2266,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2207 // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. 2266 // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
2208 // 2267 //
2209 // This workaround is to prevent silent failure of this function. 2268 // This workaround is to prevent silent failure of this function.
2210 // According to the specification on the SL Wiki, providing a position outside of the 2269 // According to the specification on the SL Wiki, providing a position outside of the
2211 if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) 2270 if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize)
2212 { 2271 {
2213 return 0; 2272 return 0;
@@ -2442,7 +2501,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2442 { 2501 {
2443 return llGetRootRotation(); 2502 return llGetRootRotation();
2444 } 2503 }
2445 2504
2446 m_host.AddScriptLPS(1); 2505 m_host.AddScriptLPS(1);
2447 Quaternion q = m_host.GetWorldRotation(); 2506 Quaternion q = m_host.GetWorldRotation();
2448 2507
@@ -2474,14 +2533,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2474 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) 2533 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
2475 q = avatar.CameraRotation; // Mouselook 2534 q = avatar.CameraRotation; // Mouselook
2476 else 2535 else
2477 q = avatar.Rotation; // Currently infrequently updated so may be inaccurate 2536 q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
2478 } 2537 }
2479 else 2538 else
2480 q = part.ParentGroup.GroupRotation; // Likely never get here but just in case 2539 q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
2481 } 2540 }
2482 else 2541 else
2483 q = part.ParentGroup.GroupRotation; // just the group rotation 2542 q = part.ParentGroup.GroupRotation; // just the group rotation
2484 return new LSL_Rotation(q.X, q.Y, q.Z, q.W); 2543
2544 return new LSL_Rotation(q);
2485 } 2545 }
2486 2546
2487 q = part.GetWorldRotation(); 2547 q = part.GetWorldRotation();
@@ -2605,8 +2665,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2605 public LSL_Vector llGetTorque() 2665 public LSL_Vector llGetTorque()
2606 { 2666 {
2607 m_host.AddScriptLPS(1); 2667 m_host.AddScriptLPS(1);
2608 Vector3 torque = m_host.ParentGroup.GetTorque(); 2668
2609 return new LSL_Vector(torque.X,torque.Y,torque.Z); 2669 return new LSL_Vector(m_host.ParentGroup.GetTorque());
2610 } 2670 }
2611 2671
2612 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local) 2672 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
@@ -2639,13 +2699,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2639 vel = m_host.ParentGroup.RootPart.Velocity; 2699 vel = m_host.ParentGroup.RootPart.Velocity;
2640 } 2700 }
2641 2701
2642 return new LSL_Vector(vel.X, vel.Y, vel.Z); 2702 return new LSL_Vector(vel);
2643 } 2703 }
2644 2704
2645 public LSL_Vector llGetAccel() 2705 public LSL_Vector llGetAccel()
2646 { 2706 {
2647 m_host.AddScriptLPS(1); 2707 m_host.AddScriptLPS(1);
2648 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); 2708
2709 return new LSL_Vector(m_host.Acceleration);
2649 } 2710 }
2650 2711
2651 public void llSetAngularVelocity(LSL_Vector avel, int local) 2712 public void llSetAngularVelocity(LSL_Vector avel, int local)
@@ -2712,7 +2773,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2712 if (m_SoundModule != null) 2773 if (m_SoundModule != null)
2713 { 2774 {
2714 m_SoundModule.SendSound(m_host.UUID, 2775 m_SoundModule.SendSound(m_host.UUID,
2715 KeyOrName(sound, AssetType.Sound), volume, false, 0, 2776 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
2716 0, false, false); 2777 0, false, false);
2717 } 2778 }
2718 } 2779 }
@@ -2722,7 +2783,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2722 m_host.AddScriptLPS(1); 2783 m_host.AddScriptLPS(1);
2723 if (m_SoundModule != null) 2784 if (m_SoundModule != null)
2724 { 2785 {
2725 m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), 2786 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2726 volume, 20, false); 2787 volume, 20, false);
2727 } 2788 }
2728 } 2789 }
@@ -2732,7 +2793,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2732 m_host.AddScriptLPS(1); 2793 m_host.AddScriptLPS(1);
2733 if (m_SoundModule != null) 2794 if (m_SoundModule != null)
2734 { 2795 {
2735 m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), 2796 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2736 volume, 20, true); 2797 volume, 20, true);
2737 } 2798 }
2738 } 2799 }
@@ -2754,7 +2815,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2754 if (m_SoundModule != null) 2815 if (m_SoundModule != null)
2755 { 2816 {
2756 m_SoundModule.SendSound(m_host.UUID, 2817 m_SoundModule.SendSound(m_host.UUID,
2757 KeyOrName(sound, AssetType.Sound), volume, false, 0, 2818 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
2758 0, true, false); 2819 0, true, false);
2759 } 2820 }
2760 } 2821 }
@@ -2766,7 +2827,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2766 if (m_SoundModule != null) 2827 if (m_SoundModule != null)
2767 { 2828 {
2768 m_SoundModule.SendSound(m_host.UUID, 2829 m_SoundModule.SendSound(m_host.UUID,
2769 KeyOrName(sound, AssetType.Sound), volume, true, 0, 0, 2830 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
2770 false, false); 2831 false, false);
2771 } 2832 }
2772 } 2833 }
@@ -2783,7 +2844,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2783 { 2844 {
2784 m_host.AddScriptLPS(1); 2845 m_host.AddScriptLPS(1);
2785 if (m_SoundModule != null) 2846 if (m_SoundModule != null)
2786 m_SoundModule.PreloadSound(m_host.UUID, KeyOrName(sound), 0); 2847 m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
2787 ScriptSleep(1000); 2848 ScriptSleep(1000);
2788 } 2849 }
2789 2850
@@ -3141,11 +3202,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3141 3202
3142 PhysicsActor pa = new_group.RootPart.PhysActor; 3203 PhysicsActor pa = new_group.RootPart.PhysActor;
3143 3204
3205 //Recoil.
3144 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) 3206 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
3145 { 3207 {
3146 float groupmass = new_group.GetMass(); 3208 float groupmass = new_group.GetMass();
3147 vel *= -groupmass; 3209 Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
3148 llApplyImpulse(vel, 0); 3210 if (recoil != Vector3.Zero)
3211 {
3212 llApplyImpulse(recoil, 0);
3213 }
3149 } 3214 }
3150 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) 3215 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
3151 return; 3216 return;
@@ -3220,7 +3285,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3220 { 3285 {
3221// m_log.Info("llSleep snoozing " + sec + "s."); 3286// m_log.Info("llSleep snoozing " + sec + "s.");
3222 m_host.AddScriptLPS(1); 3287 m_host.AddScriptLPS(1);
3223 Thread.Sleep((int)(sec * 1000)); 3288
3289 Sleep((int)(sec * 1000));
3224 } 3290 }
3225 3291
3226 public LSL_Float llGetMass() 3292 public LSL_Float llGetMass()
@@ -3268,7 +3334,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3268 3334
3269 if (!UUID.TryParse(id, out objectID)) 3335 if (!UUID.TryParse(id, out objectID))
3270 objectID = UUID.Zero; 3336 objectID = UUID.Zero;
3271 3337
3272 if (objectID == UUID.Zero && name == "") 3338 if (objectID == UUID.Zero && name == "")
3273 return; 3339 return;
3274 3340
@@ -3322,7 +3388,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3322 /// <summary> 3388 /// <summary>
3323 /// Attach the object containing this script to the avatar that owns it. 3389 /// Attach the object containing this script to the avatar that owns it.
3324 /// </summary> 3390 /// </summary>
3325 /// <param name='attachment'>The attachment point (e.g. ATTACH_CHEST)</param> 3391 /// <param name='attachmentPoint'>
3392 /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
3393 /// </param>
3326 /// <returns>true if the attach suceeded, false if it did not</returns> 3394 /// <returns>true if the attach suceeded, false if it did not</returns>
3327 public bool AttachToAvatar(int attachmentPoint) 3395 public bool AttachToAvatar(int attachmentPoint)
3328 { 3396 {
@@ -3332,7 +3400,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3332 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; 3400 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
3333 3401
3334 if (attachmentsModule != null) 3402 if (attachmentsModule != null)
3335 return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false); 3403 return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false, true);
3336 else 3404 else
3337 return false; 3405 return false;
3338 } 3406 }
@@ -3473,20 +3541,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3473 msg.offline = (byte)0; //offline; 3541 msg.offline = (byte)0; //offline;
3474 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID; 3542 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID;
3475 msg.Position = new Vector3(m_host.AbsolutePosition); 3543 msg.Position = new Vector3(m_host.AbsolutePosition);
3476 msg.RegionID = World.RegionInfo.RegionID.Guid; 3544 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
3477 msg.binaryBucket 3545
3546 Vector3 pos = m_host.AbsolutePosition;
3547 msg.binaryBucket
3478 = Util.StringToBytes256( 3548 = Util.StringToBytes256(
3479 "{0}/{1}/{2}/{3}", 3549 "{0}/{1}/{2}/{3}",
3480 World.RegionInfo.RegionName, 3550 World.RegionInfo.RegionName,
3481 (int)Math.Floor(m_host.AbsolutePosition.X), 3551 (int)Math.Floor(pos.X),
3482 (int)Math.Floor(m_host.AbsolutePosition.Y), 3552 (int)Math.Floor(pos.Y),
3483 (int)Math.Floor(m_host.AbsolutePosition.Z)); 3553 (int)Math.Floor(pos.Z));
3484 3554
3485 if (m_TransferModule != null) 3555 if (m_TransferModule != null)
3486 { 3556 {
3487 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 3557 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
3488 } 3558 }
3489 3559
3490 ScriptSleep(2000); 3560 ScriptSleep(2000);
3491 } 3561 }
3492 3562
@@ -3611,7 +3681,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3611 public void llRotLookAt(LSL_Rotation target, double strength, double damping) 3681 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3612 { 3682 {
3613 m_host.AddScriptLPS(1); 3683 m_host.AddScriptLPS(1);
3614 3684
3615 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply 3685 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
3616 // set the rotation of the object, copy that behavior 3686 // set the rotation of the object, copy that behavior
3617 PhysicsActor pa = m_host.PhysActor; 3687 PhysicsActor pa = m_host.PhysActor;
@@ -3653,7 +3723,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3653 if (presence != null) 3723 if (presence != null)
3654 { 3724 {
3655 // Do NOT try to parse UUID, animations cannot be triggered by ID 3725 // Do NOT try to parse UUID, animations cannot be triggered by ID
3656 UUID animID = InventoryKey(anim, (int)AssetType.Animation); 3726 UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
3657 if (animID == UUID.Zero) 3727 if (animID == UUID.Zero)
3658 presence.Animator.AddAnimation(anim, m_host.UUID); 3728 presence.Animator.AddAnimation(anim, m_host.UUID);
3659 else 3729 else
@@ -3675,12 +3745,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3675 3745
3676 if (presence != null) 3746 if (presence != null)
3677 { 3747 {
3678 UUID animID = KeyOrName(anim); 3748 UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
3679 3749
3680 if (animID == UUID.Zero) 3750 if (animID == UUID.Zero)
3681 presence.Animator.RemoveAnimation(anim); 3751 presence.Animator.RemoveAnimation(anim);
3682 else 3752 else
3683 presence.Animator.RemoveAnimation(animID); 3753 presence.Animator.RemoveAnimation(animID, true);
3684 } 3754 }
3685 } 3755 }
3686 } 3756 }
@@ -3753,21 +3823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3753 } 3823 }
3754 else 3824 else
3755 { 3825 {
3756 bool sitting = false; 3826 if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID))
3757 if (m_host.SitTargetAvatar == agentID)
3758 {
3759 sitting = true;
3760 }
3761 else
3762 {
3763 foreach (SceneObjectPart p in m_host.ParentGroup.Parts)
3764 {
3765 if (p.SitTargetAvatar == agentID)
3766 sitting = true;
3767 }
3768 }
3769
3770 if (sitting)
3771 { 3827 {
3772 // When agent is sitting, certain permissions are implicit if requested from sitting agent 3828 // When agent is sitting, certain permissions are implicit if requested from sitting agent
3773 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | 3829 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
@@ -3809,7 +3865,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3809 INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); 3865 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
3810 if (npcModule != null && npcModule.IsNPC(agentID, World)) 3866 if (npcModule != null && npcModule.IsNPC(agentID, World))
3811 { 3867 {
3812 if (agentID == m_host.ParentGroup.OwnerID || npcModule.GetOwner(agentID) == m_host.ParentGroup.OwnerID) 3868 if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
3813 { 3869 {
3814 lock (m_host.TaskInventory) 3870 lock (m_host.TaskInventory)
3815 { 3871 {
@@ -4184,62 +4240,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4184 public LSL_String llGetLinkName(int linknum) 4240 public LSL_String llGetLinkName(int linknum)
4185 { 4241 {
4186 m_host.AddScriptLPS(1); 4242 m_host.AddScriptLPS(1);
4187 // simplest case, this prims link number
4188 if (linknum == m_host.LinkNum || linknum == ScriptBaseClass.LINK_THIS)
4189 return m_host.Name;
4190
4191 // parse for sitting avatare-names
4192 List<String> nametable = new List<String>();
4193 World.ForEachRootScenePresence(delegate(ScenePresence presence)
4194 {
4195 SceneObjectPart sitPart = presence.ParentPart;
4196 if (sitPart != null && m_host.ParentGroup.ContainsPart(sitPart.LocalId))
4197 nametable.Add(presence.ControllingClient.Name);
4198 });
4199
4200 int totalprims = m_host.ParentGroup.PrimCount + nametable.Count;
4201 if (totalprims > m_host.ParentGroup.PrimCount)
4202 {
4203 // sitting Avatar-Name with negativ linknum / SinglePrim
4204 if (linknum < 0 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
4205 return nametable[0];
4206 // Prim-Name / SinglePrim Sitting Avatar
4207 if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
4208 return m_host.Name;
4209 // LinkNumber > of Real PrimSet = AvatarName
4210 if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims)
4211 return nametable[totalprims - linknum];
4212 }
4213 4243
4214 // Single prim 4244 ISceneEntity entity = GetLinkEntity(linknum);
4215 if (m_host.LinkNum == 0)
4216 {
4217 if (linknum == 0 || linknum == ScriptBaseClass.LINK_ROOT)
4218 return m_host.Name;
4219 else
4220 return UUID.Zero.ToString();
4221 }
4222 4245
4223 // Link set 4246 if (entity != null)
4224 SceneObjectPart part = null; 4247 return entity.Name;
4225 if (m_host.LinkNum == 1) // this is the Root prim
4226 {
4227 if (linknum < 0)
4228 part = m_host.ParentGroup.GetLinkNumPart(2);
4229 else
4230 part = m_host.ParentGroup.GetLinkNumPart(linknum);
4231 }
4232 else // this is a child prim
4233 {
4234 if (linknum < 2)
4235 part = m_host.ParentGroup.GetLinkNumPart(1);
4236 else
4237 part = m_host.ParentGroup.GetLinkNumPart(linknum);
4238 }
4239 if (part != null)
4240 return part.Name;
4241 else 4248 else
4242 return UUID.Zero.ToString(); 4249 return ScriptBaseClass.NULL_KEY;
4243 } 4250 }
4244 4251
4245 public LSL_Integer llGetInventoryNumber(int type) 4252 public LSL_Integer llGetInventoryNumber(int type)
@@ -4604,8 +4611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4604 if (presence.UserLevel >= 200) return; 4611 if (presence.UserLevel >= 200) return;
4605 4612
4606 // agent must be over the owners land 4613 // agent must be over the owners land
4607 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4614 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4608 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
4609 { 4615 {
4610 if (!World.TeleportClientHome(agentId, presence.ControllingClient)) 4616 if (!World.TeleportClientHome(agentId, presence.ControllingClient))
4611 { 4617 {
@@ -4621,6 +4627,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4621 } 4627 }
4622 } 4628 }
4623 } 4629 }
4630
4624 ScriptSleep(5000); 4631 ScriptSleep(5000);
4625 } 4632 }
4626 4633
@@ -4641,8 +4648,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4641 destination = World.RegionInfo.RegionName; 4648 destination = World.RegionInfo.RegionName;
4642 4649
4643 // agent must be over the owners land 4650 // agent must be over the owners land
4644 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4651 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4645 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
4646 { 4652 {
4647 DoLLTeleport(presence, destination, targetPos, targetLookAt); 4653 DoLLTeleport(presence, destination, targetPos, targetLookAt);
4648 } 4654 }
@@ -4673,8 +4679,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4673 if (presence.GodLevel >= 200) return; 4679 if (presence.GodLevel >= 200) return;
4674 4680
4675 // agent must be over the owners land 4681 // agent must be over the owners land
4676 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4682 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4677 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
4678 { 4683 {
4679 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); 4684 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4680 } 4685 }
@@ -4691,7 +4696,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4691 4696
4692 private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt) 4697 private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
4693 { 4698 {
4694 UUID assetID = KeyOrName(destination); 4699 UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
4695 4700
4696 // The destinaion is not an asset ID and also doesn't name a landmark. 4701 // The destinaion is not an asset ID and also doesn't name a landmark.
4697 // Use it as a sim name 4702 // Use it as a sim name
@@ -4724,7 +4729,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4724 UUID av = new UUID(); 4729 UUID av = new UUID();
4725 if (!UUID.TryParse(agent,out av)) 4730 if (!UUID.TryParse(agent,out av))
4726 { 4731 {
4727 //LSLError("First parameter to llDialog needs to be a key");
4728 return; 4732 return;
4729 } 4733 }
4730 4734
@@ -4765,7 +4769,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4765 return; 4769 return;
4766 } 4770 }
4767 // TODO: Parameter check logic required. 4771 // TODO: Parameter check logic required.
4768 m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound); 4772 m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
4769 m_host.CollisionSoundVolume = (float)impact_volume; 4773 m_host.CollisionSoundVolume = (float)impact_volume;
4770 m_host.CollisionSoundType = 1; 4774 m_host.CollisionSoundType = 1;
4771 } 4775 }
@@ -4890,7 +4894,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4890 { 4894 {
4891 if (pushrestricted) 4895 if (pushrestricted)
4892 { 4896 {
4893 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); 4897 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4894 4898
4895 // We didn't find the parcel but region is push restricted so assume it is NOT ok 4899 // We didn't find the parcel but region is push restricted so assume it is NOT ok
4896 if (targetlandObj == null) 4900 if (targetlandObj == null)
@@ -4905,7 +4909,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4905 } 4909 }
4906 else 4910 else
4907 { 4911 {
4908 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); 4912 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4909 if (targetlandObj == null) 4913 if (targetlandObj == null)
4910 { 4914 {
4911 // We didn't find the parcel but region isn't push restricted so assume it's ok 4915 // We didn't find the parcel but region isn't push restricted so assume it's ok
@@ -4935,6 +4939,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4935 } 4939 }
4936 } 4940 }
4937 } 4941 }
4942
4938 if (pushAllowed) 4943 if (pushAllowed)
4939 { 4944 {
4940 float distance = (PusheePos - m_host.AbsolutePosition).Length(); 4945 float distance = (PusheePos - m_host.AbsolutePosition).Length();
@@ -4964,17 +4969,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4964 applied_linear_impulse *= scaling_factor; 4969 applied_linear_impulse *= scaling_factor;
4965 4970
4966 } 4971 }
4972
4967 if (pusheeIsAvatar) 4973 if (pusheeIsAvatar)
4968 { 4974 {
4969 if (pusheeav != null) 4975 if (pusheeav != null)
4970 { 4976 {
4971 if (pusheeav.PhysicsActor != null) 4977 PhysicsActor pa = pusheeav.PhysicsActor;
4978
4979 if (pa != null)
4972 { 4980 {
4973 if (local != 0) 4981 if (local != 0)
4974 { 4982 {
4975 applied_linear_impulse *= m_host.GetWorldRotation(); 4983 applied_linear_impulse *= m_host.GetWorldRotation();
4976 } 4984 }
4977 pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true); 4985
4986 pa.AddForce(applied_linear_impulse, true);
4978 } 4987 }
4979 } 4988 }
4980 } 4989 }
@@ -5324,8 +5333,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5324 public LSL_Vector llGetCenterOfMass() 5333 public LSL_Vector llGetCenterOfMass()
5325 { 5334 {
5326 m_host.AddScriptLPS(1); 5335 m_host.AddScriptLPS(1);
5327 Vector3 center = m_host.GetCenterOfMass(); 5336
5328 return new LSL_Vector(center.X,center.Y,center.Z); 5337 return new LSL_Vector(m_host.GetCenterOfMass());
5329 } 5338 }
5330 5339
5331 public LSL_List llListSort(LSL_List src, int stride, int ascending) 5340 public LSL_List llListSort(LSL_List src, int stride, int ascending)
@@ -5466,7 +5475,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5466 // SL spits out an empty string for types other than key & string 5475 // SL spits out an empty string for types other than key & string
5467 // At the time of patching, LSL_Key is currently LSL_String, 5476 // At the time of patching, LSL_Key is currently LSL_String,
5468 // so the OR check may be a little redundant, but it's being done 5477 // so the OR check may be a little redundant, but it's being done
5469 // for completion and should LSL_Key ever be implemented 5478 // for completion and should LSL_Key ever be implemented
5470 // as it's own struct 5479 // as it's own struct
5471 else if (!(src.Data[index] is LSL_String || 5480 else if (!(src.Data[index] is LSL_String ||
5472 src.Data[index] is LSL_Key || 5481 src.Data[index] is LSL_Key ||
@@ -5603,8 +5612,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5603 { 5612 {
5604 m_host.AddScriptLPS(1); 5613 m_host.AddScriptLPS(1);
5605 5614
5606 return string.Join(", ", 5615 return string.Join(", ",
5607 (new List<object>(src.Data)).ConvertAll<string>(o => 5616 (new List<object>(src.Data)).ConvertAll<string>(o =>
5608 { 5617 {
5609 return o.ToString(); 5618 return o.ToString();
5610 }).ToArray()); 5619 }).ToArray());
@@ -5852,9 +5861,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5852 } 5861 }
5853 5862
5854 /// <summary> 5863 /// <summary>
5855 /// Insert the list identified by <src> into the 5864 /// Insert the list identified by <paramref name="src"/> into the
5856 /// list designated by <dest> such that the first 5865 /// list designated by <paramref name="dest"/> such that the first
5857 /// new element has the index specified by <index> 5866 /// new element has the index specified by <paramref name="index"/>
5858 /// </summary> 5867 /// </summary>
5859 5868
5860 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index) 5869 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
@@ -6182,12 +6191,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6182 } 6191 }
6183 6192
6184 ILandObject land; 6193 ILandObject land;
6185 Vector3 pos;
6186 UUID id = UUID.Zero; 6194 UUID id = UUID.Zero;
6195
6187 if (parcel || parcelOwned) 6196 if (parcel || parcelOwned)
6188 { 6197 {
6189 pos = m_host.ParentGroup.RootPart.GetWorldPosition(); 6198 land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
6190 land = World.LandChannel.GetLandObject(pos.X, pos.Y);
6191 if (land == null) 6199 if (land == null)
6192 { 6200 {
6193 id = UUID.Zero; 6201 id = UUID.Zero;
@@ -6213,20 +6221,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6213 { 6221 {
6214 if (!regionWide) 6222 if (!regionWide)
6215 { 6223 {
6216 pos = ssp.AbsolutePosition; 6224 land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
6217 land = World.LandChannel.GetLandObject(pos.X, pos.Y);
6218 if (land != null) 6225 if (land != null)
6219 { 6226 {
6220 if (parcelOwned && land.LandData.OwnerID == id || 6227 if (parcelOwned && land.LandData.OwnerID == id ||
6221 parcel && land.LandData.GlobalID == id) 6228 parcel && land.LandData.GlobalID == id)
6222 { 6229 {
6223 result.Add(ssp.UUID.ToString()); 6230 result.Add(new LSL_Key(ssp.UUID.ToString()));
6224 } 6231 }
6225 } 6232 }
6226 } 6233 }
6227 else 6234 else
6228 { 6235 {
6229 result.Add(ssp.UUID.ToString()); 6236 result.Add(new LSL_Key(ssp.UUID.ToString()));
6230 } 6237 }
6231 } 6238 }
6232 // Maximum of 100 results 6239 // Maximum of 100 results
@@ -6330,7 +6337,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6330 if (m_SoundModule != null) 6337 if (m_SoundModule != null)
6331 { 6338 {
6332 m_SoundModule.TriggerSoundLimited(m_host.UUID, 6339 m_SoundModule.TriggerSoundLimited(m_host.UUID,
6333 KeyOrName(sound, AssetType.Sound), volume, 6340 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume,
6334 bottom_south_west, top_north_east); 6341 bottom_south_west, top_north_east);
6335 } 6342 }
6336 } 6343 }
@@ -6345,14 +6352,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6345 if (presence != null) 6352 if (presence != null)
6346 { 6353 {
6347 // agent must be over the owners land 6354 // agent must be over the owners land
6348 ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); 6355 ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
6349 if (land == null) 6356 if (land == null)
6350 return; 6357 return;
6351 6358
6352 if (m_host.OwnerID == land.LandData.OwnerID) 6359 if (m_host.OwnerID == land.LandData.OwnerID)
6353 { 6360 {
6354 Vector3 pos = World.GetNearestAllowedPosition(presence, land); 6361 Vector3 p = World.GetNearestAllowedPosition(presence, land);
6355 presence.TeleportWithMomentum(pos, null); 6362 presence.TeleportWithMomentum(p, null);
6356 presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); 6363 presence.ControllingClient.SendAlertMessage("You have been ejected from this land");
6357 } 6364 }
6358 } 6365 }
@@ -6374,19 +6381,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6374 ScenePresence presence = World.GetScenePresence(key); 6381 ScenePresence presence = World.GetScenePresence(key);
6375 if (presence != null) // object is an avatar 6382 if (presence != null) // object is an avatar
6376 { 6383 {
6377 if (m_host.OwnerID 6384 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
6378 == World.LandChannel.GetLandObject(
6379 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
6380 return 1; 6385 return 1;
6381 } 6386 }
6382 else // object is not an avatar 6387 else // object is not an avatar
6383 { 6388 {
6384 SceneObjectPart obj = World.GetSceneObjectPart(key); 6389 SceneObjectPart obj = World.GetSceneObjectPart(key);
6390
6385 if (obj != null) 6391 if (obj != null)
6386 if (m_host.OwnerID 6392 {
6387 == World.LandChannel.GetLandObject( 6393 if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
6388 obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID)
6389 return 1; 6394 return 1;
6395 }
6390 } 6396 }
6391 } 6397 }
6392 6398
@@ -6494,8 +6500,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6494 // if the land is group owned and the object is group owned by the same group 6500 // if the land is group owned and the object is group owned by the same group
6495 // or 6501 // or
6496 // if the object is owned by a person with estate access. 6502 // if the object is owned by a person with estate access.
6497 6503 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
6498 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
6499 if (parcel != null) 6504 if (parcel != null)
6500 { 6505 {
6501 if (m_host.OwnerID == parcel.LandData.OwnerID || 6506 if (m_host.OwnerID == parcel.LandData.OwnerID ||
@@ -6507,14 +6512,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6507 } 6512 }
6508 } 6513 }
6509 } 6514 }
6510
6511 } 6515 }
6512
6513 } 6516 }
6514 6517
6515 public LSL_Vector llGroundSlope(LSL_Vector offset) 6518 public LSL_Vector llGroundSlope(LSL_Vector offset)
6516 { 6519 {
6517 m_host.AddScriptLPS(1); 6520 m_host.AddScriptLPS(1);
6521
6518 //Get the slope normal. This gives us the equation of the plane tangent to the slope. 6522 //Get the slope normal. This gives us the equation of the plane tangent to the slope.
6519 LSL_Vector vsn = llGroundNormal(offset); 6523 LSL_Vector vsn = llGroundNormal(offset);
6520 6524
@@ -6525,7 +6529,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6525 vsl.Normalize(); 6529 vsl.Normalize();
6526 //Normalization might be overkill here 6530 //Normalization might be overkill here
6527 6531
6528 return new LSL_Vector(vsl.X, vsl.Y, vsl.Z); 6532 vsn.x = vsl.X;
6533 vsn.y = vsl.Y;
6534 vsn.z = vsl.Z;
6535
6536 return vsn;
6529 } 6537 }
6530 6538
6531 public LSL_Vector llGroundNormal(LSL_Vector offset) 6539 public LSL_Vector llGroundNormal(LSL_Vector offset)
@@ -6575,7 +6583,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6575 //I believe the crossproduct of two normalized vectors is a normalized vector so 6583 //I believe the crossproduct of two normalized vectors is a normalized vector so
6576 //this normalization may be overkill 6584 //this normalization may be overkill
6577 6585
6578 return new LSL_Vector(vsn.X, vsn.Y, vsn.Z); 6586 return new LSL_Vector(vsn);
6579 } 6587 }
6580 6588
6581 public LSL_Vector llGroundContour(LSL_Vector offset) 6589 public LSL_Vector llGroundContour(LSL_Vector offset)
@@ -6687,6 +6695,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6687 ps.BurstSpeedMax = 1.0f; 6695 ps.BurstSpeedMax = 1.0f;
6688 ps.BurstRate = 0.1f; 6696 ps.BurstRate = 0.1f;
6689 ps.PartMaxAge = 10.0f; 6697 ps.PartMaxAge = 10.0f;
6698 ps.BurstPartCount = 1;
6690 return ps; 6699 return ps;
6691 } 6700 }
6692 6701
@@ -6710,8 +6719,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6710 6719
6711 private void SetParticleSystem(SceneObjectPart part, LSL_List rules) 6720 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6712 { 6721 {
6713
6714
6715 if (rules.Length == 0) 6722 if (rules.Length == 0)
6716 { 6723 {
6717 part.RemoveParticleSystem(); 6724 part.RemoveParticleSystem();
@@ -6802,7 +6809,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6802 break; 6809 break;
6803 6810
6804 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE: 6811 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
6805 prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1)); 6812 prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1));
6806 break; 6813 break;
6807 6814
6808 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE: 6815 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
@@ -6947,7 +6954,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6947 m_host.OwnerID, m_host.Name, destID, 6954 m_host.OwnerID, m_host.Name, destID,
6948 (byte)InstantMessageDialog.TaskInventoryOffered, 6955 (byte)InstantMessageDialog.TaskInventoryOffered,
6949 false, string.Format("'{0}'", category), 6956 false, string.Format("'{0}'", category),
6950// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 6957// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
6951// false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z), 6958// false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
6952 folderID, false, pos, 6959 folderID, false, pos,
6953 bucket, false); 6960 bucket, false);
@@ -7066,12 +7073,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7066 public LSL_String llAvatarOnLinkSitTarget(int linknum) 7073 public LSL_String llAvatarOnLinkSitTarget(int linknum)
7067 { 7074 {
7068 m_host.AddScriptLPS(1); 7075 m_host.AddScriptLPS(1);
7069 if(linknum == ScriptBaseClass.LINK_SET || 7076 if(linknum == ScriptBaseClass.LINK_SET ||
7070 linknum == ScriptBaseClass.LINK_ALL_CHILDREN || 7077 linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
7071 linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); 7078 linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
7072 7079
7073 List<SceneObjectPart> parts = GetLinkParts(linknum); 7080 List<SceneObjectPart> parts = GetLinkParts(linknum);
7074 if (parts.Count == 0) return UUID.Zero.ToString(); 7081 if (parts.Count == 0) return UUID.Zero.ToString();
7075 return parts[0].SitTargetAvatar.ToString(); 7082 return parts[0].SitTargetAvatar.ToString();
7076 } 7083 }
7077 7084
@@ -7080,7 +7087,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7080 { 7087 {
7081 m_host.AddScriptLPS(1); 7088 m_host.AddScriptLPS(1);
7082 UUID key; 7089 UUID key;
7083 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 7090 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
7091
7084 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) 7092 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
7085 { 7093 {
7086 int expires = 0; 7094 int expires = 0;
@@ -7222,20 +7230,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7222 } 7230 }
7223 if (buttons.Length > 12) 7231 if (buttons.Length > 12)
7224 { 7232 {
7225 LSLError("No more than 12 buttons can be shown"); 7233 ShoutError("button list too long, must be 12 or fewer entries");
7226 return;
7227 } 7234 }
7228 string[] buts = new string[buttons.Length]; 7235 int length = buttons.Length;
7229 for (int i = 0; i < buttons.Length; i++) 7236 if (length > 12)
7237 length = 12;
7238
7239 string[] buts = new string[length];
7240 for (int i = 0; i < length; i++)
7230 { 7241 {
7231 if (buttons.Data[i].ToString() == String.Empty) 7242 if (buttons.Data[i].ToString() == String.Empty)
7232 { 7243 {
7233 LSLError("button label cannot be blank"); 7244 ShoutError("button label cannot be blank");
7234 return; 7245 return;
7235 } 7246 }
7236 if (buttons.Data[i].ToString().Length > 24) 7247 if (buttons.Data[i].ToString().Length > 24)
7237 { 7248 {
7238 llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters"); 7249 ShoutError("button label cannot be longer than 24 characters");
7239 return; 7250 return;
7240 } 7251 }
7241 buts[i] = buttons.Data[i].ToString(); 7252 buts[i] = buttons.Data[i].ToString();
@@ -7371,6 +7382,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7371 public void llCloseRemoteDataChannel(string channel) 7382 public void llCloseRemoteDataChannel(string channel)
7372 { 7383 {
7373 m_host.AddScriptLPS(1); 7384 m_host.AddScriptLPS(1);
7385
7386 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
7387 if (xmlRpcRouter != null)
7388 {
7389 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
7390 }
7391
7374 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 7392 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7375 if (xmlrpcMod != null) 7393 if (xmlrpcMod != null)
7376 xmlrpcMod.CloseXMLRPCChannel((UUID)channel); 7394 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
@@ -7450,7 +7468,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7450 hollow = 0.70f; 7468 hollow = 0.70f;
7451 } 7469 }
7452 } 7470 }
7453 // Otherwise, hollow is limited to 95%. 7471 // Otherwise, hollow is limited to 95%.
7454 else 7472 else
7455 { 7473 {
7456 if (hollow > 0.95f) 7474 if (hollow > 0.95f)
@@ -7744,9 +7762,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7744 UUID sculptId; 7762 UUID sculptId;
7745 7763
7746 if (!UUID.TryParse(map, out sculptId)) 7764 if (!UUID.TryParse(map, out sculptId))
7747 { 7765 sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture);
7748 sculptId = InventoryKey(map, (int)AssetType.Texture);
7749 }
7750 7766
7751 if (sculptId == UUID.Zero) 7767 if (sculptId == UUID.Zero)
7752 return; 7768 return;
@@ -7843,7 +7859,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7843 physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType; 7859 physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType;
7844 physdata.Density = part.Density; 7860 physdata.Density = part.Density;
7845 physdata.Friction = part.Friction; 7861 physdata.Friction = part.Friction;
7846 physdata.Bounce = part.Bounciness; 7862 physdata.Bounce = part.Restitution;
7847 physdata.GravitationModifier = part.GravityModifier; 7863 physdata.GravitationModifier = part.GravityModifier;
7848 7864
7849 if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0) 7865 if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0)
@@ -8236,7 +8252,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8236 8252
8237 ExtraPhysicsData physdata = new ExtraPhysicsData(); 8253 ExtraPhysicsData physdata = new ExtraPhysicsData();
8238 physdata.Density = part.Density; 8254 physdata.Density = part.Density;
8239 physdata.Bounce = part.Bounciness; 8255 physdata.Bounce = part.Restitution;
8240 physdata.GravitationModifier = part.GravityModifier; 8256 physdata.GravitationModifier = part.GravityModifier;
8241 physdata.PhysShapeType = (PhysShapeType)shape_type; 8257 physdata.PhysShapeType = (PhysShapeType)shape_type;
8242 8258
@@ -8509,7 +8525,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8509 { 8525 {
8510 m_host.AddScriptLPS(1); 8526 m_host.AddScriptLPS(1);
8511 8527
8512 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 8528 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8513 8529
8514 if (land.LandData.OwnerID != m_host.OwnerID) 8530 if (land.LandData.OwnerID != m_host.OwnerID)
8515 return; 8531 return;
@@ -8523,7 +8539,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8523 { 8539 {
8524 m_host.AddScriptLPS(1); 8540 m_host.AddScriptLPS(1);
8525 8541
8526 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 8542 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8527 8543
8528 if (land.LandData.OwnerID != m_host.OwnerID) 8544 if (land.LandData.OwnerID != m_host.OwnerID)
8529 return String.Empty; 8545 return String.Empty;
@@ -8534,8 +8550,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8534 public LSL_Vector llGetRootPosition() 8550 public LSL_Vector llGetRootPosition()
8535 { 8551 {
8536 m_host.AddScriptLPS(1); 8552 m_host.AddScriptLPS(1);
8537 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, 8553
8538 m_host.ParentGroup.AbsolutePosition.Z); 8554 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
8539 } 8555 }
8540 8556
8541 /// <summary> 8557 /// <summary>
@@ -8558,13 +8574,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8558 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) 8574 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
8559 q = avatar.CameraRotation; // Mouselook 8575 q = avatar.CameraRotation; // Mouselook
8560 else 8576 else
8561 q = avatar.Rotation; // Currently infrequently updated so may be inaccurate 8577 q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
8562 else 8578 else
8563 q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case 8579 q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
8564 } 8580 }
8565 else 8581 else
8566 q = m_host.ParentGroup.GroupRotation; // just the group rotation 8582 q = m_host.ParentGroup.GroupRotation; // just the group rotation
8567 return new LSL_Rotation(q.X, q.Y, q.Z, q.W); 8583
8584 return new LSL_Rotation(q);
8568 } 8585 }
8569 8586
8570 public LSL_String llGetObjectDesc() 8587 public LSL_String llGetObjectDesc()
@@ -8731,8 +8748,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8731 8748
8732 public LSL_Vector llGetGeometricCenter() 8749 public LSL_Vector llGetGeometricCenter()
8733 { 8750 {
8734 Vector3 tmp = m_host.GetGeometricCenter(); 8751 return new LSL_Vector(m_host.GetGeometricCenter());
8735 return new LSL_Vector(tmp.X, tmp.Y, tmp.Z);
8736 } 8752 }
8737 8753
8738 public LSL_List llGetPrimitiveParams(LSL_List rules) 8754 public LSL_List llGetPrimitiveParams(LSL_List rules)
@@ -8839,9 +8855,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8839 break; 8855 break;
8840 8856
8841 case (int)ScriptBaseClass.PRIM_SIZE: 8857 case (int)ScriptBaseClass.PRIM_SIZE:
8842 res.Add(new LSL_Vector(part.Scale.X, 8858 res.Add(new LSL_Vector(part.Scale));
8843 part.Scale.Y,
8844 part.Scale.Z));
8845 break; 8859 break;
8846 8860
8847 case (int)ScriptBaseClass.PRIM_ROTATION: 8861 case (int)ScriptBaseClass.PRIM_ROTATION:
@@ -8909,16 +8923,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8909 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); 8923 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
8910 8924
8911 // float revolutions 8925 // float revolutions
8912 res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); 8926 res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
8913 // Slightly inaccurate, because an unsigned byte is being used to represent 8927 // Slightly inaccurate, because an unsigned byte is being used to represent
8914 // the entire range of floating-point values from 1.0 through 4.0 (which is how 8928 // the entire range of floating-point values from 1.0 through 4.0 (which is how
8915 // SL does it). 8929 // SL does it).
8916 // 8930 //
8917 // Using these formulas to store and retrieve PathRevolutions, it is not 8931 // Using these formulas to store and retrieve PathRevolutions, it is not
8918 // possible to use all values between 1.00 and 4.00. For instance, you can't 8932 // possible to use all values between 1.00 and 4.00. For instance, you can't
8919 // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you 8933 // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
8920 // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them 8934 // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
8921 // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar 8935 // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
8922 // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. 8936 // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
8923 // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value 8937 // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
8924 // such as 1.10. So, SL must store and retreive the actual user input rather 8938 // such as 1.10. So, SL must store and retreive the actual user input rather
@@ -9202,9 +9216,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9202 case (int)ScriptBaseClass.PRIM_DESC: 9216 case (int)ScriptBaseClass.PRIM_DESC:
9203 res.Add(new LSL_String(part.Description)); 9217 res.Add(new LSL_String(part.Description));
9204 break; 9218 break;
9205
9206 case (int)ScriptBaseClass.PRIM_ROT_LOCAL: 9219 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
9207 res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W)); 9220 res.Add(new LSL_Rotation(part.RotationOffset));
9208 break; 9221 break;
9209 9222
9210 case (int)ScriptBaseClass.PRIM_POS_LOCAL: 9223 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
@@ -10236,6 +10249,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10236 return UUID.Zero.ToString(); 10249 return UUID.Zero.ToString();
10237 } 10250 }
10238 } 10251 }
10252
10239 public LSL_String llRequestURL() 10253 public LSL_String llRequestURL()
10240 { 10254 {
10241 m_host.AddScriptLPS(1); 10255 m_host.AddScriptLPS(1);
@@ -10387,7 +10401,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10387 10401
10388 // according to the docs, this command only works if script owner and land owner are the same 10402 // according to the docs, this command only works if script owner and land owner are the same
10389 // lets add estate owners and gods, too, and use the generic permission check. 10403 // lets add estate owners and gods, too, and use the generic permission check.
10390 ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 10404 ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10391 if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; 10405 if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
10392 10406
10393 bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? 10407 bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
@@ -10710,22 +10724,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10710 m_host.AddScriptLPS(1); 10724 m_host.AddScriptLPS(1);
10711 10725
10712 if (m_item.PermsGranter == UUID.Zero) 10726 if (m_item.PermsGranter == UUID.Zero)
10713 return new LSL_Vector(); 10727 return Vector3.Zero;
10714 10728
10715 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 10729 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10716 { 10730 {
10717 ShoutError("No permissions to track the camera"); 10731 ShoutError("No permissions to track the camera");
10718 return new LSL_Vector(); 10732 return Vector3.Zero;
10719 } 10733 }
10720 10734
10721// ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 10735// ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10722 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); 10736 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
10723 if (presence != null) 10737 if (presence != null)
10724 { 10738 {
10725 LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z); 10739 LSL_Vector pos = new LSL_Vector(presence.CameraPosition);
10726 return pos; 10740 return pos;
10727 } 10741 }
10728 return new LSL_Vector(); 10742
10743 return Vector3.Zero;
10729 } 10744 }
10730 10745
10731 public LSL_Rotation llGetCameraRot() 10746 public LSL_Rotation llGetCameraRot()
@@ -10733,22 +10748,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10733 m_host.AddScriptLPS(1); 10748 m_host.AddScriptLPS(1);
10734 10749
10735 if (m_item.PermsGranter == UUID.Zero) 10750 if (m_item.PermsGranter == UUID.Zero)
10736 return new LSL_Rotation(); 10751 return Quaternion.Identity;
10737 10752
10738 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 10753 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10739 { 10754 {
10740 ShoutError("No permissions to track the camera"); 10755 ShoutError("No permissions to track the camera");
10741 return new LSL_Rotation(); 10756 return Quaternion.Identity;
10742 } 10757 }
10743 10758
10744// ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 10759// ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10745 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); 10760 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
10746 if (presence != null) 10761 if (presence != null)
10747 { 10762 {
10748 return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W); 10763 return new LSL_Rotation(presence.CameraRotation);
10749 } 10764 }
10750 10765
10751 return new LSL_Rotation(); 10766 return Quaternion.Identity;
10752 } 10767 }
10753 10768
10754 /// <summary> 10769 /// <summary>
@@ -10829,7 +10844,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10829 { 10844 {
10830 m_host.AddScriptLPS(1); 10845 m_host.AddScriptLPS(1);
10831 UUID key; 10846 UUID key;
10832 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 10847 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10833 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) 10848 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10834 { 10849 {
10835 int expires = 0; 10850 int expires = 0;
@@ -10870,7 +10885,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10870 { 10885 {
10871 m_host.AddScriptLPS(1); 10886 m_host.AddScriptLPS(1);
10872 UUID key; 10887 UUID key;
10873 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 10888 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10874 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) 10889 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
10875 { 10890 {
10876 if (UUID.TryParse(avatar, out key)) 10891 if (UUID.TryParse(avatar, out key))
@@ -10897,7 +10912,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10897 { 10912 {
10898 m_host.AddScriptLPS(1); 10913 m_host.AddScriptLPS(1);
10899 UUID key; 10914 UUID key;
10900 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 10915 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10901 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) 10916 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10902 { 10917 {
10903 if (UUID.TryParse(avatar, out key)) 10918 if (UUID.TryParse(avatar, out key))
@@ -11129,9 +11144,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11129 IHttpRequestModule httpScriptMod = 11144 IHttpRequestModule httpScriptMod =
11130 m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>(); 11145 m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
11131 List<string> param = new List<string>(); 11146 List<string> param = new List<string>();
11132 foreach (object o in parameters.Data) 11147 bool ok;
11148 Int32 flag;
11149
11150 for (int i = 0; i < parameters.Data.Length; i += 2)
11133 { 11151 {
11134 param.Add(o.ToString()); 11152 ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
11153 if (!ok || flag < 0 ||
11154 flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
11155 {
11156 throw new ScriptException("Parameter " + i.ToString() + " is an invalid flag");
11157 }
11158
11159 param.Add(parameters.Data[i].ToString()); //Add parameter flag
11160
11161 if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
11162 {
11163 param.Add(parameters.Data[i+1].ToString()); //Add parameter value
11164 }
11165 else
11166 {
11167 //Parameters are in pairs and custom header takes
11168 //arguments in pairs so adjust for header marker.
11169 ++i;
11170
11171 //Maximum of 8 headers are allowed based on the
11172 //Second Life documentation for llHTTPRequest.
11173 for (int count = 1; count <= 8; ++count)
11174 {
11175 //Enough parameters remaining for (another) header?
11176 if (parameters.Data.Length - i < 2)
11177 {
11178 //There must be at least one name/value pair for custom header
11179 if (count == 1)
11180 throw new ScriptException("Missing name/value for custom header at parameter " + i.ToString());
11181 break;
11182 }
11183
11184 if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
11185 throw new ScriptException("Name is invalid as a custom header at parameter " + i.ToString());
11186
11187 param.Add(parameters.Data[i].ToString());
11188 param.Add(parameters.Data[i+1].ToString());
11189
11190 //Have we reached the end of the list of headers?
11191 //End is marked by a string with a single digit.
11192 if (i+2 >= parameters.Data.Length ||
11193 Char.IsDigit(parameters.Data[i].ToString()[0]))
11194 {
11195 break;
11196 }
11197
11198 i += 2;
11199 }
11200 }
11135 } 11201 }
11136 11202
11137 Vector3 position = m_host.AbsolutePosition; 11203 Vector3 position = m_host.AbsolutePosition;
@@ -11263,7 +11329,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11263 public void llResetLandBanList() 11329 public void llResetLandBanList()
11264 { 11330 {
11265 m_host.AddScriptLPS(1); 11331 m_host.AddScriptLPS(1);
11266 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; 11332 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
11267 if (land.OwnerID == m_host.OwnerID) 11333 if (land.OwnerID == m_host.OwnerID)
11268 { 11334 {
11269 foreach (LandAccessEntry entry in land.ParcelAccessList) 11335 foreach (LandAccessEntry entry in land.ParcelAccessList)
@@ -11280,7 +11346,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11280 public void llResetLandPassList() 11346 public void llResetLandPassList()
11281 { 11347 {
11282 m_host.AddScriptLPS(1); 11348 m_host.AddScriptLPS(1);
11283 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; 11349 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
11284 if (land.OwnerID == m_host.OwnerID) 11350 if (land.OwnerID == m_host.OwnerID)
11285 { 11351 {
11286 foreach (LandAccessEntry entry in land.ParcelAccessList) 11352 foreach (LandAccessEntry entry in land.ParcelAccessList)
@@ -11297,12 +11363,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11297 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) 11363 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
11298 { 11364 {
11299 m_host.AddScriptLPS(1); 11365 m_host.AddScriptLPS(1);
11300 11366
11301 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y); 11367 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
11302 11368
11303 if (lo == null) 11369 if (lo == null)
11304 return 0; 11370 return 0;
11305 11371
11306 IPrimCounts pc = lo.PrimCounts; 11372 IPrimCounts pc = lo.PrimCounts;
11307 11373
11308 if (sim_wide != ScriptBaseClass.FALSE) 11374 if (sim_wide != ScriptBaseClass.FALSE)
@@ -11332,7 +11398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11332 else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP) 11398 else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
11333 return 0; // counts not implemented yet 11399 return 0; // counts not implemented yet
11334 } 11400 }
11335 11401
11336 return 0; 11402 return 0;
11337 } 11403 }
11338 11404
@@ -11517,6 +11583,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11517 case ScriptBaseClass.OBJECT_PHYSICS_COST: 11583 case ScriptBaseClass.OBJECT_PHYSICS_COST:
11518 ret.Add(new LSL_Float(0)); 11584 ret.Add(new LSL_Float(0));
11519 break; 11585 break;
11586 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11587 ret.Add(new LSL_Float(0));
11588 break;
11589 case ScriptBaseClass.OBJECT_ROOT:
11590 SceneObjectPart p = av.ParentPart;
11591 if (p != null)
11592 {
11593 ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
11594 }
11595 else
11596 {
11597 ret.Add(new LSL_String(id));
11598 }
11599 break;
11600 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11601 ret.Add(new LSL_Integer(0));
11602 break;
11603 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
11604 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
11605 break;
11606 case ScriptBaseClass.OBJECT_PHYSICS:
11607 ret.Add(new LSL_Integer(0));
11608 break;
11609 case ScriptBaseClass.OBJECT_PHANTOM:
11610 ret.Add(new LSL_Integer(0));
11611 break;
11612 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11613 ret.Add(new LSL_Integer(0));
11614 break;
11520 default: 11615 default:
11521 // Invalid or unhandled constant. 11616 // Invalid or unhandled constant.
11522 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); 11617 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
@@ -11608,6 +11703,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11608 // The value returned in SL for normal prims is prim count 11703 // The value returned in SL for normal prims is prim count
11609 ret.Add(new LSL_Float(obj.PhysicsCost)); 11704 ret.Add(new LSL_Float(obj.PhysicsCost));
11610 break; 11705 break;
11706 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11707 ret.Add(new LSL_Float(0));
11708 break;
11709 case ScriptBaseClass.OBJECT_ROOT:
11710 ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
11711 break;
11712 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11713 ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
11714 break;
11715 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
11716 byte pcode = obj.Shape.PCode;
11717 if (obj.ParentGroup.AttachmentPoint != 0
11718 || pcode == (byte)PCode.Grass
11719 || pcode == (byte)PCode.Tree
11720 || pcode == (byte)PCode.NewTree)
11721 {
11722 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
11723 }
11724 else
11725 {
11726 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
11727 }
11728 break;
11729 case ScriptBaseClass.OBJECT_PHYSICS:
11730 if (obj.ParentGroup.AttachmentPoint != 0)
11731 {
11732 ret.Add(new LSL_Integer(0)); // Always false if attached
11733 }
11734 else
11735 {
11736 ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
11737 }
11738 break;
11739 case ScriptBaseClass.OBJECT_PHANTOM:
11740 if (obj.ParentGroup.AttachmentPoint != 0)
11741 {
11742 ret.Add(new LSL_Integer(0)); // Always false if attached
11743 }
11744 else
11745 {
11746 ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
11747 }
11748 break;
11749 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11750 ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
11751 break;
11611 default: 11752 default:
11612 // Invalid or unhandled constant. 11753 // Invalid or unhandled constant.
11613 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); 11754 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
@@ -11618,7 +11759,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11618 return ret; 11759 return ret;
11619 } 11760 }
11620 } 11761 }
11621 11762
11622 return new LSL_List(); 11763 return new LSL_List();
11623 } 11764 }
11624 11765
@@ -11687,14 +11828,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11687 return UUID.Zero.ToString(); 11828 return UUID.Zero.ToString();
11688 } 11829 }
11689 11830
11831 string reqIdentifier = UUID.Random().ToString();
11832
11690 // was: UUID tid = tid = AsyncCommands. 11833 // was: UUID tid = tid = AsyncCommands.
11691 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); 11834 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11692 11835
11693 if (NotecardCache.IsCached(assetID)) 11836 if (NotecardCache.IsCached(assetID))
11694 { 11837 {
11695 AsyncCommands. 11838 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString());
11696 DataserverPlugin.DataserverReply(assetID.ToString(), 11839
11697 NotecardCache.GetLines(assetID).ToString());
11698 ScriptSleep(100); 11840 ScriptSleep(100);
11699 return tid.ToString(); 11841 return tid.ToString();
11700 } 11842 }
@@ -11710,9 +11852,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11710 string data = Encoding.UTF8.GetString(a.Data); 11852 string data = Encoding.UTF8.GetString(a.Data);
11711 //m_log.Debug(data); 11853 //m_log.Debug(data);
11712 NotecardCache.Cache(id, data); 11854 NotecardCache.Cache(id, data);
11713 AsyncCommands. 11855 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString());
11714 DataserverPlugin.DataserverReply(id.ToString(),
11715 NotecardCache.GetLines(id).ToString());
11716 }); 11856 });
11717 11857
11718 ScriptSleep(100); 11858 ScriptSleep(100);
@@ -11741,13 +11881,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11741 return UUID.Zero.ToString(); 11881 return UUID.Zero.ToString();
11742 } 11882 }
11743 11883
11884 string reqIdentifier = UUID.Random().ToString();
11885
11744 // was: UUID tid = tid = AsyncCommands. 11886 // was: UUID tid = tid = AsyncCommands.
11745 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); 11887 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11746 11888
11747 if (NotecardCache.IsCached(assetID)) 11889 if (NotecardCache.IsCached(assetID))
11748 { 11890 {
11749 AsyncCommands.DataserverPlugin.DataserverReply(assetID.ToString(), 11891 AsyncCommands.DataserverPlugin.DataserverReply(
11750 NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); 11892 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11893
11751 ScriptSleep(100); 11894 ScriptSleep(100);
11752 return tid.ToString(); 11895 return tid.ToString();
11753 } 11896 }
@@ -11763,8 +11906,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11763 string data = Encoding.UTF8.GetString(a.Data); 11906 string data = Encoding.UTF8.GetString(a.Data);
11764 //m_log.Debug(data); 11907 //m_log.Debug(data);
11765 NotecardCache.Cache(id, data); 11908 NotecardCache.Cache(id, data);
11766 AsyncCommands.DataserverPlugin.DataserverReply(id.ToString(), 11909 AsyncCommands.DataserverPlugin.DataserverReply(
11767 NotecardCache.GetLine(id, line, m_notecardLineReadCharsMax)); 11910 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11768 }); 11911 });
11769 11912
11770 ScriptSleep(100); 11913 ScriptSleep(100);
@@ -11799,7 +11942,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11799 11942
11800 LSL_List result = new LSL_List(); 11943 LSL_List result = new LSL_List();
11801 11944
11802 if (obj != null && obj.OwnerID != m_host.OwnerID) 11945 if (obj != null && obj.OwnerID == m_host.OwnerID)
11803 { 11946 {
11804 LSL_List remaining = GetPrimParams(obj, rules, ref result); 11947 LSL_List remaining = GetPrimParams(obj, rules, ref result);
11805 11948
@@ -11903,7 +12046,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11903 World.ForEachScenePresence(delegate(ScenePresence sp) 12046 World.ForEachScenePresence(delegate(ScenePresence sp)
11904 { 12047 {
11905 Vector3 ac = sp.AbsolutePosition - rayStart; 12048 Vector3 ac = sp.AbsolutePosition - rayStart;
11906 Vector3 bc = sp.AbsolutePosition - rayEnd; 12049// Vector3 bc = sp.AbsolutePosition - rayEnd;
11907 12050
11908 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); 12051 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11909 12052
@@ -11991,9 +12134,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11991 radius = Math.Abs(maxY); 12134 radius = Math.Abs(maxY);
11992 if (Math.Abs(maxZ) > radius) 12135 if (Math.Abs(maxZ) > radius)
11993 radius = Math.Abs(maxZ); 12136 radius = Math.Abs(maxZ);
11994 12137 radius = radius*1.413f;
11995 Vector3 ac = group.AbsolutePosition - rayStart; 12138 Vector3 ac = group.AbsolutePosition - rayStart;
11996 Vector3 bc = group.AbsolutePosition - rayEnd; 12139// Vector3 bc = group.AbsolutePosition - rayEnd;
11997 12140
11998 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); 12141 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11999 12142
@@ -12006,11 +12149,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12006 if (d2 > 0) 12149 if (d2 > 0)
12007 return; 12150 return;
12008 12151
12152 ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
12009 EntityIntersection intersection = group.TestIntersection(ray, true, false); 12153 EntityIntersection intersection = group.TestIntersection(ray, true, false);
12010 // Miss. 12154 // Miss.
12011 if (!intersection.HitTF) 12155 if (!intersection.HitTF)
12012 return; 12156 return;
12013 12157
12158 Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ);
12159 Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ);
12160 //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z);
12161 if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X &&
12162 intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y &&
12163 intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z))
12164 return;
12165
12014 ContactResult result = new ContactResult (); 12166 ContactResult result = new ContactResult ();
12015 result.ConsumerID = group.LocalId; 12167 result.ConsumerID = group.LocalId;
12016// result.Depth = intersection.distance; 12168// result.Depth = intersection.distance;
@@ -12226,7 +12378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12226 if (checkNonPhysical) 12378 if (checkNonPhysical)
12227 rayfilter |= RayFilterFlags.nonphysical; 12379 rayfilter |= RayFilterFlags.nonphysical;
12228 if (detectPhantom) 12380 if (detectPhantom)
12229 rayfilter |= RayFilterFlags.LSLPhanton; 12381 rayfilter |= RayFilterFlags.LSLPhantom;
12230 12382
12231 Vector3 direction = dir * ( 1/dist); 12383 Vector3 direction = dir * ( 1/dist);
12232 12384
@@ -12284,8 +12436,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12284 if (checkPhysical || checkNonPhysical || detectPhantom) 12436 if (checkPhysical || checkNonPhysical || detectPhantom)
12285 { 12437 {
12286 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); 12438 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
12287 foreach (ContactResult r in objectHits) 12439 for (int iter = 0; iter < objectHits.Length; iter++)
12288 results.Add(r); 12440 {
12441 // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler.
12442 objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart);
12443 results.Add(objectHits[iter]);
12444 }
12289 } 12445 }
12290 } 12446 }
12291 12447
@@ -12346,7 +12502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12346 else 12502 else
12347 { 12503 {
12348 ScenePresence sp = World.GetScenePresence(result.ConsumerID); 12504 ScenePresence sp = World.GetScenePresence(result.ConsumerID);
12349 /// It it a boy? a girl? 12505 /// It it a boy? a girl?
12350 if (sp != null) 12506 if (sp != null)
12351 itemID = sp.UUID; 12507 itemID = sp.UUID;
12352 } 12508 }
@@ -12358,7 +12514,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12358 list.Add(new LSL_Integer(linkNum)); 12514 list.Add(new LSL_Integer(linkNum));
12359 12515
12360 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) 12516 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
12361 list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z)); 12517 list.Add(new LSL_Vector(result.Normal));
12362 12518
12363 values++; 12519 values++;
12364 if (values >= count) 12520 if (values >= count)
@@ -13233,7 +13389,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13233 13389
13234 public static void Cache(UUID assetID, string text) 13390 public static void Cache(UUID assetID, string text)
13235 { 13391 {
13236 CacheCheck(); 13392 CheckCache();
13237 13393
13238 lock (m_Notecards) 13394 lock (m_Notecards)
13239 { 13395 {
@@ -13271,7 +13427,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13271 /// Get a notecard line. 13427 /// Get a notecard line.
13272 /// </summary> 13428 /// </summary>
13273 /// <param name="assetID"></param> 13429 /// <param name="assetID"></param>
13274 /// <param name="line">Lines start at index 0</param> 13430 /// <param name="lineNumber">Lines start at index 0</param>
13275 /// <returns></returns> 13431 /// <returns></returns>
13276 public static string GetLine(UUID assetID, int lineNumber) 13432 public static string GetLine(UUID assetID, int lineNumber)
13277 { 13433 {
@@ -13300,9 +13456,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13300 /// Get a notecard line. 13456 /// Get a notecard line.
13301 /// </summary> 13457 /// </summary>
13302 /// <param name="assetID"></param> 13458 /// <param name="assetID"></param>
13303 /// <param name="line">Lines start at index 0</param> 13459 /// <param name="lineNumber">Lines start at index 0</param>
13304 /// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para> 13460 /// <param name="maxLength">
13305 /// <returns></returns> 13461 /// Maximum length of the returned line.
13462 /// </param>
13463 /// <returns>
13464 /// If the line length is longer than <paramref name="maxLength"/>,
13465 /// the return string will be truncated.
13466 /// </returns>
13306 public static string GetLine(UUID assetID, int lineNumber, int maxLength) 13467 public static string GetLine(UUID assetID, int lineNumber, int maxLength)
13307 { 13468 {
13308 string line = GetLine(assetID, lineNumber); 13469 string line = GetLine(assetID, lineNumber);
@@ -13313,13 +13474,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13313 return line; 13474 return line;
13314 } 13475 }
13315 13476
13316 public static void CacheCheck() 13477 public static void CheckCache()
13317 { 13478 {
13318 foreach (UUID key in new List<UUID>(m_Notecards.Keys)) 13479 lock (m_Notecards)
13319 { 13480 {
13320 Notecard nc = m_Notecards[key]; 13481 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
13321 if (nc.lastRef.AddSeconds(30) < DateTime.Now) 13482 {
13322 m_Notecards.Remove(key); 13483 Notecard nc = m_Notecards[key];
13484 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
13485 m_Notecards.Remove(key);
13486 }
13323 } 13487 }
13324 } 13488 }
13325 } 13489 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
index ceb4660..1d6cb6d 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, WaitHandle 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..bd776b6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -30,6 +30,8 @@ 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;
34using log4net;
33using OpenMetaverse; 35using OpenMetaverse;
34using Nini.Config; 36using Nini.Config;
35using OpenSim; 37using OpenSim;
@@ -55,15 +57,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
55 [Serializable] 57 [Serializable]
56 public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi 58 public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi
57 { 59 {
60// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
58 internal IScriptEngine m_ScriptEngine; 62 internal IScriptEngine m_ScriptEngine;
59 internal SceneObjectPart m_host; 63 internal SceneObjectPart m_host;
60 internal TaskInventoryItem m_item; 64 internal TaskInventoryItem m_item;
61 internal bool m_MODFunctionsEnabled = false; 65 internal bool m_MODFunctionsEnabled = false;
62 internal IScriptModuleComms m_comms = null; 66 internal IScriptModuleComms m_comms = null;
63 67
64 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 68 public void Initialize(
69 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
65 { 70 {
66 m_ScriptEngine = ScriptEngine; 71 m_ScriptEngine = scriptEngine;
67 m_host = host; 72 m_host = host;
68 m_item = item; 73 m_item = item;
69 74
@@ -107,8 +112,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
107 if (message.Length > 1023) 112 if (message.Length > 1023)
108 message = message.Substring(0, 1023); 113 message = message.Substring(0, 1023);
109 114
110 World.SimChat(Utils.StringToBytes(message), 115 World.SimChat(
111 ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true); 116 Utils.StringToBytes(message),
117 ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL,
118 m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
112 119
113 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); 120 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
114 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); 121 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message);
@@ -122,8 +129,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
122 /// <returns>string result of the invocation</returns> 129 /// <returns>string result of the invocation</returns>
123 public void modInvokeN(string fname, params object[] parms) 130 public void modInvokeN(string fname, params object[] parms)
124 { 131 {
132// m_log.DebugFormat(
133// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
134// fname,
135// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
136// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
137
125 Type returntype = m_comms.LookupReturnType(fname); 138 Type returntype = m_comms.LookupReturnType(fname);
126 if (returntype != typeof(string)) 139 if (returntype != typeof(void))
127 MODError(String.Format("return type mismatch for {0}",fname)); 140 MODError(String.Format("return type mismatch for {0}",fname));
128 141
129 modInvoke(fname,parms); 142 modInvoke(fname,parms);
@@ -131,6 +144,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
131 144
132 public LSL_String modInvokeS(string fname, params object[] parms) 145 public LSL_String modInvokeS(string fname, params object[] parms)
133 { 146 {
147// m_log.DebugFormat(
148// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
149// fname,
150// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
151// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
152
134 Type returntype = m_comms.LookupReturnType(fname); 153 Type returntype = m_comms.LookupReturnType(fname);
135 if (returntype != typeof(string)) 154 if (returntype != typeof(string))
136 MODError(String.Format("return type mismatch for {0}",fname)); 155 MODError(String.Format("return type mismatch for {0}",fname));
@@ -141,6 +160,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
141 160
142 public LSL_Integer modInvokeI(string fname, params object[] parms) 161 public LSL_Integer modInvokeI(string fname, params object[] parms)
143 { 162 {
163// m_log.DebugFormat(
164// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
165// fname,
166// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
167// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
168
144 Type returntype = m_comms.LookupReturnType(fname); 169 Type returntype = m_comms.LookupReturnType(fname);
145 if (returntype != typeof(int)) 170 if (returntype != typeof(int))
146 MODError(String.Format("return type mismatch for {0}",fname)); 171 MODError(String.Format("return type mismatch for {0}",fname));
@@ -151,6 +176,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
151 176
152 public LSL_Float modInvokeF(string fname, params object[] parms) 177 public LSL_Float modInvokeF(string fname, params object[] parms)
153 { 178 {
179// m_log.DebugFormat(
180// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
181// fname,
182// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
183// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
184
154 Type returntype = m_comms.LookupReturnType(fname); 185 Type returntype = m_comms.LookupReturnType(fname);
155 if (returntype != typeof(float)) 186 if (returntype != typeof(float))
156 MODError(String.Format("return type mismatch for {0}",fname)); 187 MODError(String.Format("return type mismatch for {0}",fname));
@@ -161,6 +192,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
161 192
162 public LSL_Key modInvokeK(string fname, params object[] parms) 193 public LSL_Key modInvokeK(string fname, params object[] parms)
163 { 194 {
195// m_log.DebugFormat(
196// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
197// fname,
198// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
199// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
200
164 Type returntype = m_comms.LookupReturnType(fname); 201 Type returntype = m_comms.LookupReturnType(fname);
165 if (returntype != typeof(UUID)) 202 if (returntype != typeof(UUID))
166 MODError(String.Format("return type mismatch for {0}",fname)); 203 MODError(String.Format("return type mismatch for {0}",fname));
@@ -171,6 +208,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
171 208
172 public LSL_Vector modInvokeV(string fname, params object[] parms) 209 public LSL_Vector modInvokeV(string fname, params object[] parms)
173 { 210 {
211// m_log.DebugFormat(
212// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
213// fname,
214// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
215// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
216
174 Type returntype = m_comms.LookupReturnType(fname); 217 Type returntype = m_comms.LookupReturnType(fname);
175 if (returntype != typeof(OpenMetaverse.Vector3)) 218 if (returntype != typeof(OpenMetaverse.Vector3))
176 MODError(String.Format("return type mismatch for {0}",fname)); 219 MODError(String.Format("return type mismatch for {0}",fname));
@@ -181,6 +224,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
181 224
182 public LSL_Rotation modInvokeR(string fname, params object[] parms) 225 public LSL_Rotation modInvokeR(string fname, params object[] parms)
183 { 226 {
227// m_log.DebugFormat(
228// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
229// fname,
230// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
231// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
232
184 Type returntype = m_comms.LookupReturnType(fname); 233 Type returntype = m_comms.LookupReturnType(fname);
185 if (returntype != typeof(OpenMetaverse.Quaternion)) 234 if (returntype != typeof(OpenMetaverse.Quaternion))
186 MODError(String.Format("return type mismatch for {0}",fname)); 235 MODError(String.Format("return type mismatch for {0}",fname));
@@ -191,6 +240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
191 240
192 public LSL_List modInvokeL(string fname, params object[] parms) 241 public LSL_List modInvokeL(string fname, params object[] parms)
193 { 242 {
243// m_log.DebugFormat(
244// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
245// fname,
246// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
247// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
248
194 Type returntype = m_comms.LookupReturnType(fname); 249 Type returntype = m_comms.LookupReturnType(fname);
195 if (returntype != typeof(object[])) 250 if (returntype != typeof(object[]))
196 MODError(String.Format("return type mismatch for {0}",fname)); 251 MODError(String.Format("return type mismatch for {0}",fname));
@@ -211,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
211 { 266 {
212 llist[i] = new LSL_Float((float)result[i]); 267 llist[i] = new LSL_Float((float)result[i]);
213 } 268 }
269 else if (result[i] is double)
270 {
271 llist[i] = new LSL_Float((double)result[i]);
272 }
214 else if (result[i] is UUID) 273 else if (result[i] is UUID)
215 { 274 {
216 llist[i] = new LSL_Key(result[i].ToString()); 275 llist[i] = new LSL_Key(result[i].ToString());
@@ -248,6 +307,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
248 return ""; 307 return "";
249 } 308 }
250 309
310// m_log.DebugFormat(
311// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
312// fname,
313// string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
314// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
315
251 Type[] signature = m_comms.LookupTypeSignature(fname); 316 Type[] signature = m_comms.LookupTypeSignature(fname);
252 if (signature.Length != parms.Length) 317 if (signature.Length != parms.Length)
253 MODError(String.Format("wrong number of parameters to function {0}",fname)); 318 MODError(String.Format("wrong number of parameters to function {0}",fname));
@@ -264,6 +329,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
264 if (result != null) 329 if (result != null)
265 return result; 330 return result;
266 331
332 Type returntype = m_comms.LookupReturnType(fname);
333 if (returntype == typeof(void))
334 return null;
335
267 MODError(String.Format("Invocation of {0} failed; null return value",fname)); 336 MODError(String.Format("Invocation of {0} failed; null return value",fname));
268 } 337 }
269 catch (Exception e) 338 catch (Exception e)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 7c2f8ed..f4e4f44 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -62,6 +62,7 @@ using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
62using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; 62using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
63using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; 63using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
64using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; 64using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
65using PermissionMask = OpenSim.Framework.PermissionMask;
65 66
66namespace OpenSim.Region.ScriptEngine.Shared.Api 67namespace OpenSim.Region.ScriptEngine.Shared.Api
67{ 68{
@@ -143,9 +144,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
143 144
144 protected IUrlModule m_UrlModule = null; 145 protected IUrlModule m_UrlModule = null;
145 146
146 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 147 public void Initialize(
148 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
147 { 149 {
148 m_ScriptEngine = ScriptEngine; 150 m_ScriptEngine = scriptEngine;
149 m_host = host; 151 m_host = host;
150 m_item = item; 152 m_item = item;
151 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); 153 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
@@ -254,11 +256,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
254 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); 256 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message);
255 } 257 }
256 258
259 // Returns of the function is allowed. Throws a script exception if not allowed.
257 public void CheckThreatLevel(ThreatLevel level, string function) 260 public void CheckThreatLevel(ThreatLevel level, string function)
258 { 261 {
259 if (!m_OSFunctionsEnabled) 262 if (!m_OSFunctionsEnabled)
260 OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws 263 OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws
261 264
265 string reasonWhyNot = CheckThreatLevelTest(level, function);
266 if (!String.IsNullOrEmpty(reasonWhyNot))
267 {
268 OSSLError(reasonWhyNot);
269 }
270 }
271
272 // Check to see if function is allowed. Returns an empty string if function permitted
273 // or a string explaining why this function can't be used.
274 private string CheckThreatLevelTest(ThreatLevel level, string function)
275 {
262 if (!m_FunctionPerms.ContainsKey(function)) 276 if (!m_FunctionPerms.ContainsKey(function))
263 { 277 {
264 FunctionPerms perms = new FunctionPerms(); 278 FunctionPerms perms = new FunctionPerms();
@@ -338,10 +352,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
338 { 352 {
339 // Allow / disallow by threat level 353 // Allow / disallow by threat level
340 if (level > m_MaxThreatLevel) 354 if (level > m_MaxThreatLevel)
341 OSSLError( 355 return
342 String.Format( 356 String.Format(
343 "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", 357 "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.",
344 function, m_MaxThreatLevel, level)); 358 function, m_MaxThreatLevel, level);
345 } 359 }
346 else 360 else
347 { 361 {
@@ -351,7 +365,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
351 if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID)) 365 if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID))
352 { 366 {
353 // prim owner is in the list of allowed owners 367 // prim owner is in the list of allowed owners
354 return; 368 return String.Empty;
355 } 369 }
356 370
357 UUID ownerID = m_item.OwnerID; 371 UUID ownerID = m_item.OwnerID;
@@ -359,22 +373,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
359 //OSSL only may be used if object is in the same group as the parcel 373 //OSSL only may be used if object is in the same group as the parcel
360 if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) 374 if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER"))
361 { 375 {
362 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 376 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
363 377
364 if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) 378 if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero)
365 { 379 {
366 return; 380 return String.Empty;
367 } 381 }
368 } 382 }
369 383
370 //Only Parcelowners may use the function 384 //Only Parcelowners may use the function
371 if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER")) 385 if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER"))
372 { 386 {
373 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); 387 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
374 388
375 if (land.LandData.OwnerID == ownerID) 389 if (land.LandData.OwnerID == ownerID)
376 { 390 {
377 return; 391 return String.Empty;
378 } 392 }
379 } 393 }
380 394
@@ -384,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
384 //Only Estate Managers may use the function 398 //Only Estate Managers may use the function
385 if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) 399 if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID)
386 { 400 {
387 return; 401 return String.Empty;
388 } 402 }
389 } 403 }
390 404
@@ -393,25 +407,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
393 { 407 {
394 if (World.RegionInfo.EstateSettings.EstateOwner == ownerID) 408 if (World.RegionInfo.EstateSettings.EstateOwner == ownerID)
395 { 409 {
396 return; 410 return String.Empty;
397 } 411 }
398 } 412 }
399 413
400 if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) 414 if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID))
401 OSSLError( 415 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.", 416 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)); 417 function));
404 418
405 if (m_item.CreatorID != ownerID) 419 if (m_item.CreatorID != ownerID)
406 { 420 {
407 if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) 421 if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0)
408 OSSLError( 422 return String.Format("{0} permission denied. Script permissions error.", function);
409 String.Format("{0} permission denied. Script permissions error.",
410 function));
411 423
412 } 424 }
413 } 425 }
414 } 426 }
427 return String.Empty;
415 } 428 }
416 429
417 internal void OSSLDeprecated(string function, string replacement) 430 internal void OSSLDeprecated(string function, string replacement)
@@ -983,7 +996,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
983 if (animID == UUID.Zero) 996 if (animID == UUID.Zero)
984 target.Animator.RemoveAnimation(animation); 997 target.Animator.RemoveAnimation(animation);
985 else 998 else
986 target.Animator.RemoveAnimation(animID); 999 target.Animator.RemoveAnimation(animID, true);
987 } 1000 }
988 } 1001 }
989 } 1002 }
@@ -1214,12 +1227,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1214 sunHour += 24.0; 1227 sunHour += 24.0;
1215 1228
1216 World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; 1229 World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun;
1217 World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 1230 World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30
1218 World.RegionInfo.RegionSettings.FixedSun = sunFixed; 1231 World.RegionInfo.RegionSettings.FixedSun = sunFixed;
1219 World.RegionInfo.RegionSettings.Save(); 1232 World.RegionInfo.RegionSettings.Save();
1220 1233
1221 World.EventManager.TriggerEstateToolsSunUpdate( 1234 World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle);
1222 World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour);
1223 } 1235 }
1224 1236
1225 /// <summary> 1237 /// <summary>
@@ -1244,8 +1256,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1244 World.RegionInfo.EstateSettings.FixedSun = sunFixed; 1256 World.RegionInfo.EstateSettings.FixedSun = sunFixed;
1245 World.RegionInfo.EstateSettings.Save(); 1257 World.RegionInfo.EstateSettings.Save();
1246 1258
1247 World.EventManager.TriggerEstateToolsSunUpdate( 1259 World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle);
1248 World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour);
1249 } 1260 }
1250 1261
1251 /// <summary> 1262 /// <summary>
@@ -1501,8 +1512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1501 1512
1502 m_host.AddScriptLPS(1); 1513 m_host.AddScriptLPS(1);
1503 1514
1504 ILandObject land 1515 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
1505 = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
1506 1516
1507 if (land.LandData.OwnerID != m_host.OwnerID) 1517 if (land.LandData.OwnerID != m_host.OwnerID)
1508 return; 1518 return;
@@ -1518,8 +1528,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1518 1528
1519 m_host.AddScriptLPS(1); 1529 m_host.AddScriptLPS(1);
1520 1530
1521 ILandObject land 1531 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
1522 = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
1523 1532
1524 if (land.LandData.OwnerID != m_host.OwnerID) 1533 if (land.LandData.OwnerID != m_host.OwnerID)
1525 { 1534 {
@@ -1569,6 +1578,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1569 } 1578 }
1570 } 1579 }
1571 1580
1581 public string osGetPhysicsEngineType()
1582 {
1583 // High because it can be used to target attacks to known weaknesses
1584 // This would allow a new class of griefer scripts that don't even
1585 // require their user to know what they are doing (see script
1586 // kiddie)
1587 // Because it would be nice if scripts didn't blow up if the information
1588 // about the physics engine, this function returns an empty string if
1589 // the user does not have permission to see it. This as opposed to
1590 // throwing an exception.
1591 m_host.AddScriptLPS(1);
1592 string ret = String.Empty;
1593 if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType")))
1594 {
1595 if (m_ScriptEngine.World.PhysicsScene != null)
1596 {
1597 ret = m_ScriptEngine.World.PhysicsScene.EngineType;
1598 // An old physics engine might have an uninitialized engine type
1599 if (ret == null)
1600 ret = "unknown";
1601 }
1602 }
1603
1604 return ret;
1605 }
1606
1572 public string osGetSimulatorVersion() 1607 public string osGetSimulatorVersion()
1573 { 1608 {
1574 // High because it can be used to target attacks to known weaknesses 1609 // High because it can be used to target attacks to known weaknesses
@@ -1619,7 +1654,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1619 } 1654 }
1620 } 1655 }
1621 1656
1622 public Object osParseJSONNew(string JSON) 1657 private Object osParseJSONNew(string JSON)
1623 { 1658 {
1624 CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); 1659 CheckThreatLevel(ThreatLevel.None, "osParseJSONNew");
1625 1660
@@ -1762,8 +1797,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1762 taskItem.InvType = (int)InventoryType.Notecard; 1797 taskItem.InvType = (int)InventoryType.Notecard;
1763 taskItem.OwnerID = m_host.OwnerID; 1798 taskItem.OwnerID = m_host.OwnerID;
1764 taskItem.CreatorID = m_host.OwnerID; 1799 taskItem.CreatorID = m_host.OwnerID;
1765 taskItem.BasePermissions = (uint)PermissionMask.All; 1800 taskItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1766 taskItem.CurrentPermissions = (uint)PermissionMask.All; 1801 taskItem.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1767 taskItem.EveryonePermissions = 0; 1802 taskItem.EveryonePermissions = 0;
1768 taskItem.NextPermissions = (uint)PermissionMask.All; 1803 taskItem.NextPermissions = (uint)PermissionMask.All;
1769 taskItem.GroupID = m_host.GroupID; 1804 taskItem.GroupID = m_host.GroupID;
@@ -2136,9 +2171,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2136 CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); 2171 CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI");
2137 m_host.AddScriptLPS(1); 2172 m_host.AddScriptLPS(1);
2138 2173
2139 string HomeURI = String.Empty;
2140 IConfigSource config = m_ScriptEngine.ConfigSource; 2174 IConfigSource config = m_ScriptEngine.ConfigSource;
2175 string HomeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI",
2176 new string[] { "Startup", "Hypergrid" }, String.Empty);
2177
2178 if (!string.IsNullOrEmpty(HomeURI))
2179 return HomeURI;
2141 2180
2181 // Legacy. Remove soon!
2142 if (config.Configs["LoginService"] != null) 2182 if (config.Configs["LoginService"] != null)
2143 HomeURI = config.Configs["LoginService"].GetString("SRV_HomeURI", HomeURI); 2183 HomeURI = config.Configs["LoginService"].GetString("SRV_HomeURI", HomeURI);
2144 2184
@@ -2153,9 +2193,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2153 CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); 2193 CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI");
2154 m_host.AddScriptLPS(1); 2194 m_host.AddScriptLPS(1);
2155 2195
2156 string gatekeeperURI = String.Empty;
2157 IConfigSource config = m_ScriptEngine.ConfigSource; 2196 IConfigSource config = m_ScriptEngine.ConfigSource;
2197 string gatekeeperURI = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
2198 new string[] { "Startup", "Hypergrid" }, String.Empty);
2199
2200 if (!string.IsNullOrEmpty(gatekeeperURI))
2201 return gatekeeperURI;
2158 2202
2203 // Legacy. Remove soon!
2159 if (config.Configs["GridService"] != null) 2204 if (config.Configs["GridService"] != null)
2160 gatekeeperURI = config.Configs["GridService"].GetString("Gatekeeper", gatekeeperURI); 2205 gatekeeperURI = config.Configs["GridService"].GetString("Gatekeeper", gatekeeperURI);
2161 2206
@@ -2532,13 +2577,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2532 ScenePresence sp = World.GetScenePresence(npcId); 2577 ScenePresence sp = World.GetScenePresence(npcId);
2533 2578
2534 if (sp != null) 2579 if (sp != null)
2535 { 2580 return new LSL_Vector(sp.AbsolutePosition);
2536 Vector3 pos = sp.AbsolutePosition;
2537 return new LSL_Vector(pos.X, pos.Y, pos.Z);
2538 }
2539 } 2581 }
2540 2582
2541 return new LSL_Vector(0, 0, 0); 2583 return Vector3.Zero;
2542 } 2584 }
2543 2585
2544 public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) 2586 public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
@@ -2595,21 +2637,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2595 { 2637 {
2596 UUID npcId; 2638 UUID npcId;
2597 if (!UUID.TryParse(npc.m_string, out npcId)) 2639 if (!UUID.TryParse(npc.m_string, out npcId))
2598 return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); 2640 return new LSL_Rotation(Quaternion.Identity);
2599 2641
2600 if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) 2642 if (!npcModule.CheckPermissions(npcId, m_host.OwnerID))
2601 return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); 2643 return new LSL_Rotation(Quaternion.Identity);
2602 2644
2603 ScenePresence sp = World.GetScenePresence(npcId); 2645 ScenePresence sp = World.GetScenePresence(npcId);
2604 2646
2605 if (sp != null) 2647 if (sp != null)
2606 { 2648 return new LSL_Rotation(sp.GetWorldRotation());
2607 Quaternion rot = sp.Rotation;
2608 return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W);
2609 }
2610 } 2649 }
2611 2650
2612 return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); 2651 return Quaternion.Identity;
2613 } 2652 }
2614 2653
2615 public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) 2654 public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation)
@@ -3055,20 +3094,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3055 3094
3056 UUID avatarId = new UUID(avatar); 3095 UUID avatarId = new UUID(avatar);
3057 ScenePresence presence = World.GetScenePresence(avatarId); 3096 ScenePresence presence = World.GetScenePresence(avatarId);
3058 Vector3 pos = m_host.GetWorldPosition(); 3097
3059 bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z)); 3098 if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition()))
3060 if (result)
3061 { 3099 {
3062 if (presence != null) 3100 float health = presence.Health;
3063 { 3101 health += (float)healing;
3064 float health = presence.Health; 3102
3065 health += (float)healing; 3103 if (health >= 100)
3066 if (health >= 100) 3104 health = 100;
3067 { 3105
3068 health = 100; 3106 presence.setHealthWithUpdate(health);
3069 }
3070 presence.setHealthWithUpdate(health);
3071 }
3072 } 3107 }
3073 } 3108 }
3074 3109
@@ -3145,8 +3180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3145 if (avatar != null && avatar.UUID != m_host.OwnerID) 3180 if (avatar != null && avatar.UUID != m_host.OwnerID)
3146 { 3181 {
3147 result.Add(new LSL_String(avatar.UUID.ToString())); 3182 result.Add(new LSL_String(avatar.UUID.ToString()));
3148 OpenMetaverse.Vector3 ap = avatar.AbsolutePosition; 3183 result.Add(new LSL_Vector(avatar.AbsolutePosition));
3149 result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z));
3150 result.Add(new LSL_String(avatar.Name)); 3184 result.Add(new LSL_String(avatar.Name));
3151 } 3185 }
3152 }); 3186 });
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 4dd795d..884f07c 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}
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/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs
index d173db0..6d218a6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index c447d1f..a652cb8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -259,7 +259,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
259 259
260 string osGetScriptEngineName(); 260 string osGetScriptEngineName();
261 string osGetSimulatorVersion(); 261 string osGetSimulatorVersion();
262 Object osParseJSONNew(string JSON); 262 string osGetPhysicsEngineType();
263 Hashtable osParseJSON(string JSON); 263 Hashtable osParseJSON(string JSON);
264 264
265 void osMessageObject(key objectUUID,string message); 265 void osMessageObject(key objectUUID,string message);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index 0dd5a57..2f8154d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -356,6 +356,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
356 public const int HTTP_MIMETYPE = 1; 356 public const int HTTP_MIMETYPE = 1;
357 public const int HTTP_BODY_MAXLENGTH = 2; 357 public const int HTTP_BODY_MAXLENGTH = 2;
358 public const int HTTP_VERIFY_CERT = 3; 358 public const int HTTP_VERIFY_CERT = 3;
359 public const int HTTP_VERBOSE_THROTTLE = 4;
360 public const int HTTP_CUSTOM_HEADER = 5;
361 public const int HTTP_PRAGMA_NO_CACHE = 6;
359 362
360 public const int PRIM_MATERIAL = 2; 363 public const int PRIM_MATERIAL = 2;
361 public const int PRIM_PHYSICS = 3; 364 public const int PRIM_PHYSICS = 3;
@@ -557,6 +560,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
557 public const int OBJECT_SERVER_COST = 14; 560 public const int OBJECT_SERVER_COST = 14;
558 public const int OBJECT_STREAMING_COST = 15; 561 public const int OBJECT_STREAMING_COST = 15;
559 public const int OBJECT_PHYSICS_COST = 16; 562 public const int OBJECT_PHYSICS_COST = 16;
563 public const int OBJECT_CHARACTER_TIME = 17;
564 public const int OBJECT_ROOT = 18;
565 public const int OBJECT_ATTACHED_POINT = 19;
566 public const int OBJECT_PATHFINDING_TYPE = 20;
567 public const int OBJECT_PHYSICS = 21;
568 public const int OBJECT_PHANTOM = 22;
569 public const int OBJECT_TEMP_ON_REZ = 23;
570
571 // Pathfinding types
572 public const int OPT_OTHER = -1;
573 public const int OPT_LEGACY_LINKSET = 0;
574 public const int OPT_AVATAR = 1;
575 public const int OPT_CHARACTER = 2;
576 public const int OPT_WALKABLE = 3;
577 public const int OPT_STATIC_OBSTACLE = 4;
578 public const int OPT_MATERIAL_VOLUME = 5;
579 public const int OPT_EXCLUSION_VOLUME = 6;
560 580
561 // for llGetAgentList 581 // for llGetAgentList
562 public const int AGENT_LIST_PARCEL = 1; 582 public const int AGENT_LIST_PARCEL = 1;
@@ -619,7 +639,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
619 public const int TOUCH_INVALID_FACE = -1; 639 public const int TOUCH_INVALID_FACE = -1;
620 public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0); 640 public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0);
621 public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR; 641 public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR;
622 642
623 // constants for llGetPrimMediaParams/llSetPrimMediaParams 643 // constants for llGetPrimMediaParams/llSetPrimMediaParams
624 public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0; 644 public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0;
625 public const int PRIM_MEDIA_CONTROLS = 1; 645 public const int PRIM_MEDIA_CONTROLS = 1;
@@ -636,10 +656,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
636 public const int PRIM_MEDIA_WHITELIST = 12; 656 public const int PRIM_MEDIA_WHITELIST = 12;
637 public const int PRIM_MEDIA_PERMS_INTERACT = 13; 657 public const int PRIM_MEDIA_PERMS_INTERACT = 13;
638 public const int PRIM_MEDIA_PERMS_CONTROL = 14; 658 public const int PRIM_MEDIA_PERMS_CONTROL = 14;
639 659
640 public const int PRIM_MEDIA_CONTROLS_STANDARD = 0; 660 public const int PRIM_MEDIA_CONTROLS_STANDARD = 0;
641 public const int PRIM_MEDIA_CONTROLS_MINI = 1; 661 public const int PRIM_MEDIA_CONTROLS_MINI = 1;
642 662
643 public const int PRIM_MEDIA_PERM_NONE = 0; 663 public const int PRIM_MEDIA_PERM_NONE = 0;
644 public const int PRIM_MEDIA_PERM_OWNER = 1; 664 public const int PRIM_MEDIA_PERM_OWNER = 1;
645 public const int PRIM_MEDIA_PERM_GROUP = 2; 665 public const int PRIM_MEDIA_PERM_GROUP = 2;
@@ -672,7 +692,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
672 public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f"; 692 public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f";
673 public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; 693 public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903";
674 public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"; 694 public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361";
675 695
676 // Constants for osGetRegionStats 696 // Constants for osGetRegionStats
677 public const int STATS_TIME_DILATION = 0; 697 public const int STATS_TIME_DILATION = 0;
678 public const int STATS_SIM_FPS = 1; 698 public const int STATS_SIM_FPS = 1;
@@ -725,7 +745,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
725 public static readonly LSLInteger RC_GET_ROOT_KEY = 2; 745 public static readonly LSLInteger RC_GET_ROOT_KEY = 2;
726 public static readonly LSLInteger RC_GET_LINK_NUM = 4; 746 public static readonly LSLInteger RC_GET_LINK_NUM = 4;
727 747
728 public static readonly LSLInteger RCERR_UNKNOWN = -1; 748 public static readonly LSLInteger RCERR_UNKNOWN = -1;
729 public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; 749 public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
730 public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = -3; 750 public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = -3;
731 751
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index afa9ae0..b63773b 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();
@@ -430,11 +435,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
430 return m_OSSL_Functions.osParseJSON(JSON); 435 return m_OSSL_Functions.osParseJSON(JSON);
431 } 436 }
432 437
433 public Object osParseJSONNew(string JSON)
434 {
435 return m_OSSL_Functions.osParseJSONNew(JSON);
436 }
437
438 public void osMessageObject(key objectUUID,string message) 438 public void osMessageObject(key objectUUID,string message)
439 { 439 {
440 m_OSSL_Functions.osMessageObject(objectUUID,message); 440 m_OSSL_Functions.osMessageObject(objectUUID,message);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs
index 573a803..b1825ac 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs
index f6d5d41..342dbff 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs
index 97dd0f6..9e32f40 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs
@@ -31,7 +31,6 @@ using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using log4net; 32using log4net;
33using Tools; 33using Tools;
34
35using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
36 35
37namespace OpenSim.Region.ScriptEngine.Shared.CodeTools 36namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
@@ -49,6 +48,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
49 private List<string> m_warnings = new List<string>(); 48 private List<string> m_warnings = new List<string>();
50 private IScriptModuleComms m_comms = null; 49 private IScriptModuleComms m_comms = null;
51 50
51 private bool m_insertCoopTerminationChecks;
52 private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();";
53
54 /// <summary>
55 /// Keep a record of the previous node when we do the parsing.
56 /// </summary>
57 /// <remarks>
58 /// We do this here because the parser generated by CSTools does not retain a reference to its parent node.
59 /// The previous node is required so we can correctly insert co-op termination checks when required.
60 /// </remarks>
61// private SYMBOL m_previousNode;
62
52 /// <summary> 63 /// <summary>
53 /// Creates an 'empty' CSCodeGenerator instance. 64 /// Creates an 'empty' CSCodeGenerator instance.
54 /// </summary> 65 /// </summary>
@@ -58,9 +69,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
58 ResetCounters(); 69 ResetCounters();
59 } 70 }
60 71
61 public CSCodeGenerator(IScriptModuleComms comms) 72 public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks)
62 { 73 {
63 m_comms = comms; 74 m_comms = comms;
75 m_insertCoopTerminationChecks = insertCoopTerminationChecks;
64 ResetCounters(); 76 ResetCounters();
65 } 77 }
66 78
@@ -155,7 +167,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
155 // here's the payload 167 // here's the payload
156 retstr += GenerateLine(); 168 retstr += GenerateLine();
157 foreach (SYMBOL s in m_astRoot.kids) 169 foreach (SYMBOL s in m_astRoot.kids)
158 retstr += GenerateNode(s); 170 retstr += GenerateNode(m_astRoot, s);
159 171
160 // close braces! 172 // close braces!
161 m_braceCount--; 173 m_braceCount--;
@@ -165,7 +177,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
165 177
166 // Removes all carriage return characters which may be generated in Windows platform. Is there 178 // Removes all carriage return characters which may be generated in Windows platform. Is there
167 // cleaner way of doing this? 179 // cleaner way of doing this?
168 retstr=retstr.Replace("\r", ""); 180 retstr = retstr.Replace("\r", "");
169 181
170 return retstr; 182 return retstr;
171 } 183 }
@@ -191,9 +203,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
191 /// Recursively called to generate each type of node. Will generate this 203 /// Recursively called to generate each type of node. Will generate this
192 /// node, then all it's children. 204 /// node, then all it's children.
193 /// </summary> 205 /// </summary>
206 /// <param name="previousSymbol">The parent node.</param>
194 /// <param name="s">The current node to generate code for.</param> 207 /// <param name="s">The current node to generate code for.</param>
195 /// <returns>String containing C# code for SYMBOL s.</returns> 208 /// <returns>String containing C# code for SYMBOL s.</returns>
196 private string GenerateNode(SYMBOL s) 209 private string GenerateNode(SYMBOL previousSymbol, SYMBOL s)
197 { 210 {
198 string retstr = String.Empty; 211 string retstr = String.Empty;
199 212
@@ -207,11 +220,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
207 else if (s is State) 220 else if (s is State)
208 retstr += GenerateState((State) s); 221 retstr += GenerateState((State) s);
209 else if (s is CompoundStatement) 222 else if (s is CompoundStatement)
210 retstr += GenerateCompoundStatement((CompoundStatement) s); 223 retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s);
211 else if (s is Declaration) 224 else if (s is Declaration)
212 retstr += GenerateDeclaration((Declaration) s); 225 retstr += GenerateDeclaration((Declaration) s);
213 else if (s is Statement) 226 else if (s is Statement)
214 retstr += GenerateStatement((Statement) s); 227 retstr += GenerateStatement(previousSymbol, (Statement) s);
215 else if (s is ReturnStatement) 228 else if (s is ReturnStatement)
216 retstr += GenerateReturnStatement((ReturnStatement) s); 229 retstr += GenerateReturnStatement((ReturnStatement) s);
217 else if (s is JumpLabel) 230 else if (s is JumpLabel)
@@ -261,7 +274,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
261 else 274 else
262 { 275 {
263 foreach (SYMBOL kid in s.kids) 276 foreach (SYMBOL kid in s.kids)
264 retstr += GenerateNode(kid); 277 retstr += GenerateNode(s, kid);
265 } 278 }
266 279
267 return retstr; 280 return retstr;
@@ -295,7 +308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
295 retstr += GenerateLine(")"); 308 retstr += GenerateLine(")");
296 309
297 foreach (SYMBOL kid in remainingKids) 310 foreach (SYMBOL kid in remainingKids)
298 retstr += GenerateNode(kid); 311 retstr += GenerateNode(gf, kid);
299 312
300 return retstr; 313 return retstr;
301 } 314 }
@@ -312,7 +325,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
312 foreach (SYMBOL s in gv.kids) 325 foreach (SYMBOL s in gv.kids)
313 { 326 {
314 retstr += Indent(); 327 retstr += Indent();
315 retstr += GenerateNode(s); 328 retstr += GenerateNode(gv, s);
316 retstr += GenerateLine(";"); 329 retstr += GenerateLine(";");
317 } 330 }
318 331
@@ -365,7 +378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
365 retstr += GenerateLine(")"); 378 retstr += GenerateLine(")");
366 379
367 foreach (SYMBOL kid in remainingKids) 380 foreach (SYMBOL kid in remainingKids)
368 retstr += GenerateNode(kid); 381 retstr += GenerateNode(se, kid);
369 382
370 return retstr; 383 return retstr;
371 } 384 }
@@ -404,7 +417,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
404 417
405 foreach (SYMBOL s in al.kids) 418 foreach (SYMBOL s in al.kids)
406 { 419 {
407 retstr += GenerateNode(s); 420 retstr += GenerateNode(al, s);
408 if (0 < comma--) 421 if (0 < comma--)
409 retstr += Generate(", "); 422 retstr += Generate(", ");
410 } 423 }
@@ -417,7 +430,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
417 /// </summary> 430 /// </summary>
418 /// <param name="cs">The CompoundStatement node.</param> 431 /// <param name="cs">The CompoundStatement node.</param>
419 /// <returns>String containing C# code for CompoundStatement cs.</returns> 432 /// <returns>String containing C# code for CompoundStatement cs.</returns>
420 private string GenerateCompoundStatement(CompoundStatement cs) 433 private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs)
421 { 434 {
422 string retstr = String.Empty; 435 string retstr = String.Empty;
423 436
@@ -425,8 +438,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
425 retstr += GenerateIndentedLine("{"); 438 retstr += GenerateIndentedLine("{");
426 m_braceCount++; 439 m_braceCount++;
427 440
441 if (m_insertCoopTerminationChecks)
442 {
443 // We have to check in event functions as well because the user can manually call these.
444 if (previousSymbol is GlobalFunctionDefinition
445 || previousSymbol is WhileStatement
446 || previousSymbol is DoWhileStatement
447 || previousSymbol is ForLoop
448 || previousSymbol is StateEvent)
449 retstr += GenerateIndentedLine(m_coopTerminationCheck);
450 }
451
428 foreach (SYMBOL kid in cs.kids) 452 foreach (SYMBOL kid in cs.kids)
429 retstr += GenerateNode(kid); 453 retstr += GenerateNode(cs, kid);
430 454
431 // closing brace 455 // closing brace
432 m_braceCount--; 456 m_braceCount--;
@@ -450,10 +474,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
450 /// </summary> 474 /// </summary>
451 /// <param name="s">The Statement node.</param> 475 /// <param name="s">The Statement node.</param>
452 /// <returns>String containing C# code for Statement s.</returns> 476 /// <returns>String containing C# code for Statement s.</returns>
453 private string GenerateStatement(Statement s) 477 private string GenerateStatement(SYMBOL previousSymbol, Statement s)
454 { 478 {
455 string retstr = String.Empty; 479 string retstr = String.Empty;
456 bool printSemicolon = true; 480 bool printSemicolon = true;
481 bool transformToBlock = false;
482
483 if (m_insertCoopTerminationChecks)
484 {
485 // A non-braced single line do while structure cannot contain multiple statements.
486 // So to insert the termination check we change this to a braced control structure instead.
487 if (previousSymbol is WhileStatement
488 || previousSymbol is DoWhileStatement
489 || previousSymbol is ForLoop)
490 {
491 transformToBlock = true;
492
493 // FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented.
494 retstr += GenerateIndentedLine("{");
495
496 retstr += GenerateIndentedLine(m_coopTerminationCheck);
497 }
498 }
457 499
458 retstr += Indent(); 500 retstr += Indent();
459 501
@@ -466,12 +508,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
466 // (MONO) error. 508 // (MONO) error.
467 if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) 509 if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count))
468 foreach (SYMBOL kid in s.kids) 510 foreach (SYMBOL kid in s.kids)
469 retstr += GenerateNode(kid); 511 retstr += GenerateNode(s, kid);
470 } 512 }
471 513
472 if (printSemicolon) 514 if (printSemicolon)
473 retstr += GenerateLine(";"); 515 retstr += GenerateLine(";");
474 516
517 if (transformToBlock)
518 {
519 // FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent
520 retstr += GenerateIndentedLine("}");
521 }
522
475 return retstr; 523 return retstr;
476 } 524 }
477 525
@@ -487,10 +535,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
487 List<string> identifiers = new List<string>(); 535 List<string> identifiers = new List<string>();
488 checkForMultipleAssignments(identifiers, a); 536 checkForMultipleAssignments(identifiers, a);
489 537
490 retstr += GenerateNode((SYMBOL) a.kids.Pop()); 538 retstr += GenerateNode(a, (SYMBOL) a.kids.Pop());
491 retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); 539 retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
492 foreach (SYMBOL kid in a.kids) 540 foreach (SYMBOL kid in a.kids)
493 retstr += GenerateNode(kid); 541 retstr += GenerateNode(a, kid);
494 542
495 return retstr; 543 return retstr;
496 } 544 }
@@ -563,7 +611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
563 retstr += Generate("return ", rs); 611 retstr += Generate("return ", rs);
564 612
565 foreach (SYMBOL kid in rs.kids) 613 foreach (SYMBOL kid in rs.kids)
566 retstr += GenerateNode(kid); 614 retstr += GenerateNode(rs, kid);
567 615
568 return retstr; 616 return retstr;
569 } 617 }
@@ -575,7 +623,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
575 /// <returns>String containing C# code for JumpLabel jl.</returns> 623 /// <returns>String containing C# code for JumpLabel jl.</returns>
576 private string GenerateJumpLabel(JumpLabel jl) 624 private string GenerateJumpLabel(JumpLabel jl)
577 { 625 {
578 return Generate(String.Format("{0}:", CheckName(jl.LabelName)), jl) + " NoOp();\n"; 626 string labelStatement;
627
628 if (m_insertCoopTerminationChecks)
629 labelStatement = m_coopTerminationCheck + "\n";
630 else
631 labelStatement = "NoOp();\n";
632
633 return Generate(String.Format("{0}: ", CheckName(jl.LabelName)), jl) + labelStatement;
579 } 634 }
580 635
581 /// <summary> 636 /// <summary>
@@ -598,14 +653,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
598 string retstr = String.Empty; 653 string retstr = String.Empty;
599 654
600 retstr += GenerateIndented("if (", ifs); 655 retstr += GenerateIndented("if (", ifs);
601 retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); 656 retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
602 retstr += GenerateLine(")"); 657 retstr += GenerateLine(")");
603 658
604 // CompoundStatement handles indentation itself but we need to do it 659 // CompoundStatement handles indentation itself but we need to do it
605 // otherwise. 660 // otherwise.
606 bool indentHere = ifs.kids.Top is Statement; 661 bool indentHere = ifs.kids.Top is Statement;
607 if (indentHere) m_braceCount++; 662 if (indentHere) m_braceCount++;
608 retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); 663 retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
609 if (indentHere) m_braceCount--; 664 if (indentHere) m_braceCount--;
610 665
611 if (0 < ifs.kids.Count) // do it again for an else 666 if (0 < ifs.kids.Count) // do it again for an else
@@ -614,7 +669,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
614 669
615 indentHere = ifs.kids.Top is Statement; 670 indentHere = ifs.kids.Top is Statement;
616 if (indentHere) m_braceCount++; 671 if (indentHere) m_braceCount++;
617 retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); 672 retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
618 if (indentHere) m_braceCount--; 673 if (indentHere) m_braceCount--;
619 } 674 }
620 675
@@ -641,14 +696,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
641 string retstr = String.Empty; 696 string retstr = String.Empty;
642 697
643 retstr += GenerateIndented("while (", ws); 698 retstr += GenerateIndented("while (", ws);
644 retstr += GenerateNode((SYMBOL) ws.kids.Pop()); 699 retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
645 retstr += GenerateLine(")"); 700 retstr += GenerateLine(")");
646 701
647 // CompoundStatement handles indentation itself but we need to do it 702 // CompoundStatement handles indentation itself but we need to do it
648 // otherwise. 703 // otherwise.
649 bool indentHere = ws.kids.Top is Statement; 704 bool indentHere = ws.kids.Top is Statement;
650 if (indentHere) m_braceCount++; 705 if (indentHere) m_braceCount++;
651 retstr += GenerateNode((SYMBOL) ws.kids.Pop()); 706 retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
652 if (indentHere) m_braceCount--; 707 if (indentHere) m_braceCount--;
653 708
654 return retstr; 709 return retstr;
@@ -669,11 +724,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
669 // otherwise. 724 // otherwise.
670 bool indentHere = dws.kids.Top is Statement; 725 bool indentHere = dws.kids.Top is Statement;
671 if (indentHere) m_braceCount++; 726 if (indentHere) m_braceCount++;
672 retstr += GenerateNode((SYMBOL) dws.kids.Pop()); 727 retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
673 if (indentHere) m_braceCount--; 728 if (indentHere) m_braceCount--;
674 729
675 retstr += GenerateIndented("while (", dws); 730 retstr += GenerateIndented("while (", dws);
676 retstr += GenerateNode((SYMBOL) dws.kids.Pop()); 731 retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
677 retstr += GenerateLine(");"); 732 retstr += GenerateLine(");");
678 733
679 return retstr; 734 return retstr;
@@ -702,7 +757,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
702 retstr += Generate("; "); 757 retstr += Generate("; ");
703 // for (x = 0; x < 10; x++) 758 // for (x = 0; x < 10; x++)
704 // ^^^^^^ 759 // ^^^^^^
705 retstr += GenerateNode((SYMBOL) fl.kids.Pop()); 760 retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
706 retstr += Generate("; "); 761 retstr += Generate("; ");
707 // for (x = 0; x < 10; x++) 762 // for (x = 0; x < 10; x++)
708 // ^^^ 763 // ^^^
@@ -713,7 +768,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
713 // otherwise. 768 // otherwise.
714 bool indentHere = fl.kids.Top is Statement; 769 bool indentHere = fl.kids.Top is Statement;
715 if (indentHere) m_braceCount++; 770 if (indentHere) m_braceCount++;
716 retstr += GenerateNode((SYMBOL) fl.kids.Pop()); 771 retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
717 if (indentHere) m_braceCount--; 772 if (indentHere) m_braceCount--;
718 773
719 return retstr; 774 return retstr;
@@ -758,7 +813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
758 while (s is ParenthesisExpression) 813 while (s is ParenthesisExpression)
759 s = (SYMBOL)s.kids.Pop(); 814 s = (SYMBOL)s.kids.Pop();
760 815
761 retstr += GenerateNode(s); 816 retstr += GenerateNode(fls, s);
762 if (0 < comma--) 817 if (0 < comma--)
763 retstr += Generate(", "); 818 retstr += Generate(", ");
764 } 819 }
@@ -779,20 +834,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
779 { 834 {
780 // special case handling for logical and/or, see Mantis 3174 835 // special case handling for logical and/or, see Mantis 3174
781 retstr += "((bool)("; 836 retstr += "((bool)(";
782 retstr += GenerateNode((SYMBOL)be.kids.Pop()); 837 retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
783 retstr += "))"; 838 retstr += "))";
784 retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); 839 retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be);
785 retstr += "((bool)("; 840 retstr += "((bool)(";
786 foreach (SYMBOL kid in be.kids) 841 foreach (SYMBOL kid in be.kids)
787 retstr += GenerateNode(kid); 842 retstr += GenerateNode(be, kid);
788 retstr += "))"; 843 retstr += "))";
789 } 844 }
790 else 845 else
791 { 846 {
792 retstr += GenerateNode((SYMBOL)be.kids.Pop()); 847 retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
793 retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); 848 retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
794 foreach (SYMBOL kid in be.kids) 849 foreach (SYMBOL kid in be.kids)
795 retstr += GenerateNode(kid); 850 retstr += GenerateNode(be, kid);
796 } 851 }
797 852
798 return retstr; 853 return retstr;
@@ -808,7 +863,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
808 string retstr = String.Empty; 863 string retstr = String.Empty;
809 864
810 retstr += Generate(ue.UnarySymbol, ue); 865 retstr += Generate(ue.UnarySymbol, ue);
811 retstr += GenerateNode((SYMBOL) ue.kids.Pop()); 866 retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop());
812 867
813 return retstr; 868 return retstr;
814 } 869 }
@@ -824,7 +879,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
824 879
825 retstr += Generate("("); 880 retstr += Generate("(");
826 foreach (SYMBOL kid in pe.kids) 881 foreach (SYMBOL kid in pe.kids)
827 retstr += GenerateNode(kid); 882 retstr += GenerateNode(pe, kid);
828 retstr += Generate(")"); 883 retstr += Generate(")");
829 884
830 return retstr; 885 return retstr;
@@ -861,7 +916,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
861 916
862 // we wrap all typecasted statements in parentheses 917 // we wrap all typecasted statements in parentheses
863 retstr += Generate(String.Format("({0}) (", te.TypecastType), te); 918 retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
864 retstr += GenerateNode((SYMBOL) te.kids.Pop()); 919 retstr += GenerateNode(te, (SYMBOL) te.kids.Pop());
865 retstr += Generate(")"); 920 retstr += Generate(")");
866 921
867 return retstr; 922 return retstr;
@@ -931,7 +986,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
931 } 986 }
932 987
933 foreach (SYMBOL kid in fc.kids) 988 foreach (SYMBOL kid in fc.kids)
934 retstr += GenerateNode(kid); 989 retstr += GenerateNode(fc, kid);
935 990
936 retstr += Generate(")"); 991 retstr += Generate(")");
937 992
@@ -980,11 +1035,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
980 string retstr = String.Empty; 1035 string retstr = String.Empty;
981 1036
982 retstr += Generate(String.Format("new {0}(", vc.Type), vc); 1037 retstr += Generate(String.Format("new {0}(", vc.Type), vc);
983 retstr += GenerateNode((SYMBOL) vc.kids.Pop()); 1038 retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
984 retstr += Generate(", "); 1039 retstr += Generate(", ");
985 retstr += GenerateNode((SYMBOL) vc.kids.Pop()); 1040 retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
986 retstr += Generate(", "); 1041 retstr += Generate(", ");
987 retstr += GenerateNode((SYMBOL) vc.kids.Pop()); 1042 retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
988 retstr += Generate(")"); 1043 retstr += Generate(")");
989 1044
990 return retstr; 1045 return retstr;
@@ -1000,13 +1055,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
1000 string retstr = String.Empty; 1055 string retstr = String.Empty;
1001 1056
1002 retstr += Generate(String.Format("new {0}(", rc.Type), rc); 1057 retstr += Generate(String.Format("new {0}(", rc.Type), rc);
1003 retstr += GenerateNode((SYMBOL) rc.kids.Pop()); 1058 retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1004 retstr += Generate(", "); 1059 retstr += Generate(", ");
1005 retstr += GenerateNode((SYMBOL) rc.kids.Pop()); 1060 retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1006 retstr += Generate(", "); 1061 retstr += Generate(", ");
1007 retstr += GenerateNode((SYMBOL) rc.kids.Pop()); 1062 retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1008 retstr += Generate(", "); 1063 retstr += Generate(", ");
1009 retstr += GenerateNode((SYMBOL) rc.kids.Pop()); 1064 retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1010 retstr += Generate(")"); 1065 retstr += Generate(")");
1011 1066
1012 return retstr; 1067 return retstr;
@@ -1024,7 +1079,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
1024 retstr += Generate(String.Format("new {0}(", lc.Type), lc); 1079 retstr += Generate(String.Format("new {0}(", lc.Type), lc);
1025 1080
1026 foreach (SYMBOL kid in lc.kids) 1081 foreach (SYMBOL kid in lc.kids)
1027 retstr += GenerateNode(kid); 1082 retstr += GenerateNode(lc, kid);
1028 1083
1029 retstr += Generate(")"); 1084 retstr += Generate(")");
1030 1085
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
index 03be2ab..b71afe3 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
@@ -72,6 +72,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
72 private bool CompileWithDebugInformation; 72 private bool CompileWithDebugInformation;
73 private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase); 73 private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
74 private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase); 74 private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase);
75 private bool m_insertCoopTerminationCalls;
75 76
76 private string FilePrefix; 77 private string FilePrefix;
77 private string ScriptEnginesPath = null; 78 private string ScriptEnginesPath = null;
@@ -95,20 +96,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
95 private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps = 96 private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps =
96 new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>(); 97 new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>();
97 98
99 public bool in_startup = true;
100
98 public Compiler(IScriptEngine scriptEngine) 101 public Compiler(IScriptEngine scriptEngine)
99 { 102 {
100 m_scriptEngine = scriptEngine;; 103 m_scriptEngine = scriptEngine;
101 ScriptEnginesPath = scriptEngine.ScriptEnginePath; 104 ScriptEnginesPath = scriptEngine.ScriptEnginePath;
102 ReadConfig(); 105 ReadConfig();
103 } 106 }
104 107
105 public bool in_startup = true;
106 public void ReadConfig() 108 public void ReadConfig()
107 { 109 {
108 // Get some config 110 // Get some config
109 WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); 111 WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false);
110 CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); 112 CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true);
111 bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); 113 bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true);
114 m_insertCoopTerminationCalls = m_scriptEngine.Config.GetString("ScriptStopStrategy", "abort") == "co-op";
112 115
113 // Get file prefix from scriptengine name and make it file system safe: 116 // Get file prefix from scriptengine name and make it file system safe:
114 FilePrefix = "CommonCompiler"; 117 FilePrefix = "CommonCompiler";
@@ -386,7 +389,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
386 if (language == enumCompileType.lsl) 389 if (language == enumCompileType.lsl)
387 { 390 {
388 // Its LSL, convert it to C# 391 // Its LSL, convert it to C#
389 LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms); 392 LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls);
390 compileScript = LSL_Converter.Convert(Script); 393 compileScript = LSL_Converter.Convert(Script);
391 394
392 // copy converter warnings into our warnings. 395 // copy converter warnings into our warnings.
@@ -411,16 +414,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
411 { 414 {
412 case enumCompileType.cs: 415 case enumCompileType.cs:
413 case enumCompileType.lsl: 416 case enumCompileType.lsl:
414 compileScript = CreateCSCompilerScript(compileScript); 417 compileScript = CreateCSCompilerScript(
418 compileScript,
419 m_scriptEngine.ScriptClassName,
420 m_scriptEngine.ScriptBaseClassName,
421 m_scriptEngine.ScriptBaseClassParameters);
415 break; 422 break;
416 case enumCompileType.vb: 423 case enumCompileType.vb:
417 compileScript = CreateVBCompilerScript(compileScript); 424 compileScript = CreateVBCompilerScript(
425 compileScript, m_scriptEngine.ScriptClassName, m_scriptEngine.ScriptBaseClassName);
418 break; 426 break;
419// case enumCompileType.js: 427// case enumCompileType.js:
420// compileScript = CreateJSCompilerScript(compileScript); 428// compileScript = CreateJSCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName);
421// break; 429// break;
422 case enumCompileType.yp: 430 case enumCompileType.yp:
423 compileScript = CreateYPCompilerScript(compileScript); 431 compileScript = CreateYPCompilerScript(
432 compileScript, m_scriptEngine.ScriptClassName,m_scriptEngine.ScriptBaseClassName);
424 break; 433 break;
425 } 434 }
426 435
@@ -451,43 +460,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
451// return compileScript; 460// return compileScript;
452// } 461// }
453 462
454 private static string CreateCSCompilerScript(string compileScript) 463 private static string CreateCSCompilerScript(
464 string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters)
455 { 465 {
456 compileScript = String.Empty + 466 compileScript = string.Format(
457 "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + 467@"using OpenSim.Region.ScriptEngine.Shared;
458 String.Empty + "namespace SecondLife { " + 468using System.Collections.Generic;
459 String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + 469
460 @"public Script() { } " + 470namespace SecondLife
461 compileScript + 471{{
462 "} }\r\n"; 472 public class {0} : {1}
473 {{
474 public {0}({2}) : base({3}) {{}}
475{4}
476 }}
477}}",
478 className,
479 baseClassName,
480 constructorParameters != null
481 ? string.Join(", ", Array.ConvertAll<ParameterInfo, string>(constructorParameters, pi => pi.ToString()))
482 : "",
483 constructorParameters != null
484 ? string.Join(", ", Array.ConvertAll<ParameterInfo, string>(constructorParameters, pi => pi.Name))
485 : "",
486 compileScript);
487
463 return compileScript; 488 return compileScript;
464 } 489 }
465 490
466 private static string CreateYPCompilerScript(string compileScript) 491 private static string CreateYPCompilerScript(string compileScript, string className, string baseClassName)
467 { 492 {
468 compileScript = String.Empty + 493 compileScript = String.Empty +
469 "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + 494 "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " +
470 "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + 495 "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" +
471 String.Empty + "namespace SecondLife { " + 496 String.Empty + "namespace SecondLife { " +
472 String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + 497 String.Empty + "public class " + className + " : " + baseClassName + " { \r\n" +
473 //@"public Script() { } " + 498 //@"public Script() { } " +
474 @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + 499 @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " +
475 @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + 500 @"public " + className + "() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " +
476
477 compileScript + 501 compileScript +
478 "} }\r\n"; 502 "} }\r\n";
503
479 return compileScript; 504 return compileScript;
480 } 505 }
481 506
482 private static string CreateVBCompilerScript(string compileScript) 507 private static string CreateVBCompilerScript(string compileScript, string className, string baseClassName)
483 { 508 {
484 compileScript = String.Empty + 509 compileScript = String.Empty +
485 "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + 510 "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " +
486 String.Empty + "NameSpace SecondLife:" + 511 String.Empty + "NameSpace SecondLife:" +
487 String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + 512 String.Empty + "Public Class " + className + ": Inherits " + baseClassName +
488 "\r\nPublic Sub New()\r\nEnd Sub: " + 513 "\r\nPublic Sub New()\r\nEnd Sub: " +
489 compileScript + 514 compileScript +
490 ":End Class :End Namespace\r\n"; 515 ":End Class :End Namespace\r\n";
516
491 return compileScript; 517 return compileScript;
492 } 518 }
493 519
@@ -549,6 +575,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
549 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, 575 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
550 "OpenMetaverseTypes.dll")); 576 "OpenMetaverseTypes.dll"));
551 577
578 if (m_scriptEngine.ScriptReferencedAssemblies != null)
579 Array.ForEach<string>(
580 m_scriptEngine.ScriptReferencedAssemblies,
581 a => parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, a)));
582
552 if (lang == enumCompileType.yp) 583 if (lang == enumCompileType.yp)
553 { 584 {
554 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, 585 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
@@ -631,13 +662,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
631 { 662 {
632 string severity = CompErr.IsWarning ? "Warning" : "Error"; 663 string severity = CompErr.IsWarning ? "Warning" : "Error";
633 664
634 KeyValuePair<int, int> lslPos; 665 KeyValuePair<int, int> errorPos;
635 666
636 // Show 5 errors max, but check entire list for errors 667 // Show 5 errors max, but check entire list for errors
637 668
638 if (severity == "Error") 669 if (severity == "Error")
639 { 670 {
640 lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); 671 // C# scripts will not have a linemap since theres no line translation involved.
672 if (!m_lineMaps.ContainsKey(assembly))
673 errorPos = new KeyValuePair<int, int>(CompErr.Line, CompErr.Column);
674 else
675 errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
676
641 string text = CompErr.ErrorText; 677 string text = CompErr.ErrorText;
642 678
643 // Use LSL type names 679 // Use LSL type names
@@ -647,7 +683,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
647 // The Second Life viewer's script editor begins 683 // The Second Life viewer's script editor begins
648 // countingn lines and columns at 0, so we subtract 1. 684 // countingn lines and columns at 0, so we subtract 1.
649 errtext += String.Format("({0},{1}): {4} {2}: {3}\n", 685 errtext += String.Format("({0},{1}): {4} {2}: {3}\n",
650 lslPos.Key - 1, lslPos.Value - 1, 686 errorPos.Key - 1, errorPos.Value - 1,
651 CompErr.ErrorNumber, text, severity); 687 CompErr.ErrorNumber, text, severity);
652 hadErrors = true; 688 hadErrors = true;
653 } 689 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs
index c65caa8..5b5c4fd 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
index 470e1a1..48964b6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 771db0c..26850c4 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,66 +201,124 @@ 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 /// <returns>false if load failed, true if suceeded</returns>
256 public bool Load(AppDomain dom, string assembly, StateSource stateSource)
257 {
258 m_Assembly = assembly;
259 m_stateSource = stateSource;
230 260
231 ApiManager am = new ApiManager(); 261 ApiManager am = new ApiManager();
232 262
233 foreach (string api in am.GetApis()) 263 foreach (string api in am.GetApis())
234 { 264 {
235 m_Apis[api] = am.CreateApi(api); 265 m_Apis[api] = am.CreateApi(api);
236 m_Apis[api].Initialize(engine, part, ScriptTask); 266 m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle);
237 } 267 }
238 268
239 try 269 try
240 { 270 {
271 object[] constructorParams;
272
273 Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly));
274 Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript");
275
276 if (scriptType != null)
277 {
278 constructorParams = new object[] { m_coopSleepHandle };
279 }
280 else if (!m_coopTermination)
281 {
282 scriptType = scriptAssembly.GetType("SecondLife.Script");
283 constructorParams = null;
284 }
285 else
286 {
287 m_log.ErrorFormat(
288 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination"
289 + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run"
290 + " or by deleting these files manually.",
291 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly);
292
293 return false;
294 }
295
296// m_log.DebugFormat(
297// "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}",
298// scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name);
299
241 if (dom != System.AppDomain.CurrentDomain) 300 if (dom != System.AppDomain.CurrentDomain)
242 m_Script = (IScript)dom.CreateInstanceAndUnwrap( 301 m_Script
302 = (IScript)dom.CreateInstanceAndUnwrap(
243 Path.GetFileNameWithoutExtension(assembly), 303 Path.GetFileNameWithoutExtension(assembly),
244 "SecondLife.Script"); 304 scriptType.FullName,
305 false,
306 BindingFlags.Default,
307 null,
308 constructorParams,
309 null,
310 null,
311 null);
245 else 312 else
246 m_Script = (IScript)Assembly.Load( 313 m_Script
247 Path.GetFileNameWithoutExtension(assembly)).CreateInstance( 314 = (IScript)scriptAssembly.CreateInstance(
248 "SecondLife.Script"); 315 scriptType.FullName,
316 false,
317 BindingFlags.Default,
318 null,
319 constructorParams,
320 null,
321 null);
249 322
250 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 323 //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
251 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 324 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
@@ -254,8 +327,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
254 catch (Exception e) 327 catch (Exception e)
255 { 328 {
256 m_log.ErrorFormat( 329 m_log.ErrorFormat(
257 "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", 330 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}",
258 assembly, e.Message, e.StackTrace); 331 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace);
332
333 return false;
259 } 334 }
260 335
261 try 336 try
@@ -267,16 +342,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
267 342
268// // m_log.Debug("[Script] Script instance created"); 343// // m_log.Debug("[Script] Script instance created");
269 344
270 part.SetScriptEvents(ItemID, 345 Part.SetScriptEvents(ItemID,
271 (int)m_Script.GetStateEventFlags(State)); 346 (int)m_Script.GetStateEventFlags(State));
272 } 347 }
273 catch (Exception e) 348 catch (Exception e)
274 { 349 {
275 m_log.ErrorFormat( 350 m_log.ErrorFormat(
276 "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", 351 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}",
277 assembly, e.Message, e.StackTrace); 352 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace);
278 353
279 return; 354 return false;
280 } 355 }
281 356
282 m_SaveState = true; 357 m_SaveState = true;
@@ -309,7 +384,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
309 384
310// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); 385// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName);
311 386
312 part.SetScriptEvents(ItemID, 387 Part.SetScriptEvents(ItemID,
313 (int)m_Script.GetStateEventFlags(State)); 388 (int)m_Script.GetStateEventFlags(State));
314 389
315 if (!Running) 390 if (!Running)
@@ -329,15 +404,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
329 else 404 else
330 { 405 {
331 m_log.WarnFormat( 406 m_log.WarnFormat(
332 "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", 407 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.",
333 savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); 408 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
334 } 409 }
335 } 410 }
336 catch (Exception e) 411 catch (Exception e)
337 { 412 {
338 m_log.ErrorFormat( 413 m_log.ErrorFormat(
339 "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", 414 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}",
340 savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); 415 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace);
341 } 416 }
342 } 417 }
343// else 418// else
@@ -348,6 +423,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
348// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); 423// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false);
349 424
350// } 425// }
426
427 return true;
351 } 428 }
352 429
353 public void Init() 430 public void Init()
@@ -521,9 +598,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
521 } 598 }
522 599
523 // Wait for the current event to complete. 600 // Wait for the current event to complete.
524 if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) 601 if (!m_InSelfDelete)
525 { 602 {
526 return true; 603 if (!m_coopTermination)
604 {
605 // If we're not co-operative terminating then try and wait for the event to complete before stopping
606 if (workItem.Wait(timeout))
607 return true;
608 }
609 else
610 {
611 if (DebugLevel >= 1)
612 m_log.DebugFormat(
613 "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}",
614 ScriptName, ItemID, PrimName, ObjectID);
615
616 // This will terminate the event on next handle check by the script.
617 m_coopSleepHandle.Set();
618
619 // For now, we will wait forever since the event should always cleanly terminate once LSL loop
620 // checking is implemented. May want to allow a shorter timeout option later.
621 if (workItem.Wait(Timeout.Infinite))
622 {
623 if (DebugLevel >= 1)
624 m_log.DebugFormat(
625 "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}",
626 ScriptName, ItemID, PrimName, ObjectID);
627
628 return true;
629 }
630 }
527 } 631 }
528 632
529 lock (EventQueue) 633 lock (EventQueue)
@@ -536,11 +640,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
536 640
537 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then 641 // 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). 642 // forcibly abort the work item (this aborts the underlying thread).
643 // Co-operative termination should never reach this point.
539 if (!m_InSelfDelete) 644 if (!m_InSelfDelete)
540 { 645 {
541// m_log.ErrorFormat( 646 m_log.DebugFormat(
542// "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", 647 "[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); 648 ScriptName, ItemID, PrimName, LocalID, timeout);
544 649
545 workItem.Abort(); 650 workItem.Abort();
546 } 651 }
@@ -696,19 +801,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
696 { 801 {
697 802
698// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); 803// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
804 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
805
806 if (DebugLevel >= 2)
807 m_log.DebugFormat(
808 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
809 data.EventName,
810 ScriptName,
811 part.Name,
812 part.LocalId,
813 part.ParentGroup.Name,
814 part.ParentGroup.UUID,
815 part.AbsolutePosition,
816 part.ParentGroup.Scene.Name);
699 817
700 m_DetectParams = data.DetectParams; 818 m_DetectParams = data.DetectParams;
701 819
702 if (data.EventName == "state") // Hardcoded state change 820 if (data.EventName == "state") // Hardcoded state change
703 { 821 {
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(); 822 State = data.Params[0].ToString();
823
824 if (DebugLevel >= 1)
825 m_log.DebugFormat(
826 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
827 State,
828 ScriptName,
829 part.Name,
830 part.LocalId,
831 part.ParentGroup.Name,
832 part.ParentGroup.UUID,
833 part.AbsolutePosition,
834 part.ParentGroup.Scene.Name);
835
707 AsyncCommandManager.RemoveScript(Engine, 836 AsyncCommandManager.RemoveScript(Engine,
708 LocalID, ItemID); 837 LocalID, ItemID);
709 838
710 SceneObjectPart part = Engine.World.GetSceneObjectPart(
711 LocalID);
712 if (part != null) 839 if (part != null)
713 { 840 {
714 part.SetScriptEvents(ItemID, 841 part.SetScriptEvents(ItemID,
@@ -720,8 +847,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
720 if (Engine.World.PipeEventsForScript(LocalID) || 847 if (Engine.World.PipeEventsForScript(LocalID) ||
721 data.EventName == "control") // Don't freeze avies! 848 data.EventName == "control") // Don't freeze avies!
722 { 849 {
723 SceneObjectPart part = Engine.World.GetSceneObjectPart(
724 LocalID);
725 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", 850 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
726 // PrimName, ScriptName, data.EventName, State); 851 // PrimName, ScriptName, data.EventName, State);
727 852
@@ -763,7 +888,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
763 m_InEvent = false; 888 m_InEvent = false;
764 m_CurrentEvent = String.Empty; 889 m_CurrentEvent = String.Empty;
765 890
766 if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) 891 if ((!(e is TargetInvocationException)
892 || (!(e.InnerException is SelfDeleteException)
893 && !(e.InnerException is ScriptDeleteException)
894 && !(e.InnerException is ScriptCoopStopException)))
895 && !(e is ThreadAbortException))
767 { 896 {
768 try 897 try
769 { 898 {
@@ -776,6 +905,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
776 ChatTypeEnum.DebugChannel, 2147483647, 905 ChatTypeEnum.DebugChannel, 2147483647,
777 part.AbsolutePosition, 906 part.AbsolutePosition,
778 part.Name, part.UUID, false); 907 part.Name, part.UUID, false);
908
909
910 m_log.DebugFormat(
911 "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
912 ScriptName,
913 PrimName,
914 part.UUID,
915 part.AbsolutePosition,
916 part.ParentGroup.Scene.Name,
917 text.Replace("\n", "\\n"),
918 e.InnerException);
779 } 919 }
780 catch (Exception) 920 catch (Exception)
781 { 921 {
@@ -802,6 +942,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
802 if (part != null) 942 if (part != null)
803 part.Inventory.RemoveInventoryItem(ItemID); 943 part.Inventory.RemoveInventoryItem(ItemID);
804 } 944 }
945 else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException))
946 {
947 if (DebugLevel >= 1)
948 m_log.DebugFormat(
949 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
950 PrimName, ScriptName, data.EventName, State);
951 }
805 } 952 }
806 } 953 }
807 } 954 }
@@ -810,6 +957,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
810 // script engine to run the next event. 957 // script engine to run the next event.
811 lock (EventQueue) 958 lock (EventQueue)
812 { 959 {
960 EventsProcessed++;
961
813 if (EventQueue.Count > 0 && Running && !ShuttingDown) 962 if (EventQueue.Count > 0 && Running && !ShuttingDown)
814 { 963 {
815 m_CurrentWorkItem = Engine.QueueEventHandler(this); 964 m_CurrentWorkItem = Engine.QueueEventHandler(this);
@@ -834,7 +983,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
834 return (DateTime.Now - m_EventStart).Seconds; 983 return (DateTime.Now - m_EventStart).Seconds;
835 } 984 }
836 985
837 public void ResetScript() 986 public void ResetScript(int timeout)
838 { 987 {
839 if (m_Script == null) 988 if (m_Script == null)
840 return; 989 return;
@@ -844,7 +993,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
844 RemoveState(); 993 RemoveState();
845 ReleaseControls(); 994 ReleaseControls();
846 995
847 Stop(0); 996 Stop(timeout);
848 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 997 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
849 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; 998 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
850 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; 999 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
@@ -1015,7 +1164,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1015 "({0}): {1}", scriptLine - 1, 1164 "({0}): {1}", scriptLine - 1,
1016 e.InnerException.Message); 1165 e.InnerException.Message);
1017 1166
1018 System.Console.WriteLine(e.ToString()+"\n");
1019 return message; 1167 return message;
1020 } 1168 }
1021 } 1169 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs
new file mode 100644
index 0000000..ac822c6
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs
@@ -0,0 +1,513 @@
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.Threading;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Scripting.WorldComm;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.ScriptEngine.XEngine;
39using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41
42namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests
43{
44 /// <summary>
45 /// Test that co-operative script thread termination is working correctly.
46 /// </summary>
47 [TestFixture]
48 public class CoopTerminationTests : OpenSimTestCase
49 {
50 private TestScene m_scene;
51 private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine;
52
53 private AutoResetEvent m_chatEvent;
54 private AutoResetEvent m_stoppedEvent;
55
56 private OSChatMessage m_osChatMessageReceived;
57
58 /// <summary>
59 /// Number of chat messages received so far. Reset before each test.
60 /// </summary>
61 private int m_chatMessagesReceived;
62
63 /// <summary>
64 /// Number of chat messages expected. m_chatEvent is not fired until this number is reached or exceeded.
65 /// </summary>
66 private int m_chatMessagesThreshold;
67
68 [SetUp]
69 public void Init()
70 {
71 m_osChatMessageReceived = null;
72 m_chatMessagesReceived = 0;
73 m_chatMessagesThreshold = 0;
74 m_chatEvent = new AutoResetEvent(false);
75 m_stoppedEvent = new AutoResetEvent(false);
76
77 //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin");
78// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
79 m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine();
80
81 IniConfigSource configSource = new IniConfigSource();
82
83 IConfig startupConfig = configSource.AddConfig("Startup");
84 startupConfig.Set("DefaultScriptEngine", "XEngine");
85
86 IConfig xEngineConfig = configSource.AddConfig("XEngine");
87 xEngineConfig.Set("Enabled", "true");
88 xEngineConfig.Set("StartDelay", "0");
89
90 // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
91 // to AssemblyResolver.OnAssemblyResolve fails.
92 xEngineConfig.Set("AppDomainLoading", "false");
93
94 xEngineConfig.Set("ScriptStopStrategy", "co-op");
95
96 // Make sure loops aren't actually being terminated by a script delay wait.
97 xEngineConfig.Set("ScriptDelayFactor", 0);
98
99 // This is really just set for debugging the test.
100 xEngineConfig.Set("WriteScriptSourceToDebugFile", true);
101
102 // Set to false if we need to debug test so the old scripts don't get wiped before each separate test
103// xEngineConfig.Set("DeleteScriptsOnStartup", false);
104
105 // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination
106 // has an effect - without it tests will fail due to a 120 second wait for the event to finish.
107 xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000);
108
109 m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource);
110 SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine);
111 m_scene.StartScripts();
112 }
113
114 /// <summary>
115 /// Test co-operative termination on derez of an object containing a script with a long-running event.
116 /// </summary>
117 /// <remarks>
118 /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts
119 /// within the build itself.
120 /// </remarks>
121 [Test]
122 public void TestStopOnLongSleep()
123 {
124 TestHelpers.InMethod();
125// TestHelpers.EnableLogging();
126
127 string script =
128@"default
129{
130 state_entry()
131 {
132 llSay(0, ""Thin Lizzy"");
133 llSleep(60);
134 }
135}";
136
137 TestStop(script);
138 }
139
140 [Test]
141 public void TestNoStopOnSingleStatementForLoop()
142 {
143 TestHelpers.InMethod();
144// TestHelpers.EnableLogging();
145
146 string script =
147@"default
148{
149 state_entry()
150 {
151 integer i = 0;
152 for (i = 0; i <= 1; i++) llSay(0, ""Iter "" + (string)i);
153 }
154}";
155
156 TestSingleStatementNoStop(script);
157 }
158
159 [Test]
160 public void TestStopOnLongSingleStatementForLoop()
161 {
162 TestHelpers.InMethod();
163// TestHelpers.EnableLogging();
164
165 string script =
166@"default
167{
168 state_entry()
169 {
170 integer i = 0;
171 llSay(0, ""Thin Lizzy"");
172
173 for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i);
174 }
175}";
176
177 TestStop(script);
178 }
179
180 [Test]
181 public void TestStopOnLongCompoundStatementForLoop()
182 {
183 TestHelpers.InMethod();
184// TestHelpers.EnableLogging();
185
186 string script =
187@"default
188{
189 state_entry()
190 {
191 integer i = 0;
192 llSay(0, ""Thin Lizzy"");
193
194 for (i = 0; i < 2147483647; i++)
195 {
196 llSay(0, ""Iter "" + (string)i);
197 }
198 }
199}";
200
201 TestStop(script);
202 }
203
204 [Test]
205 public void TestNoStopOnSingleStatementWhileLoop()
206 {
207 TestHelpers.InMethod();
208// TestHelpers.EnableLogging();
209
210 string script =
211@"default
212{
213 state_entry()
214 {
215 integer i = 0;
216 while (i < 2) llSay(0, ""Iter "" + (string)i++);
217 }
218}";
219
220 TestSingleStatementNoStop(script);
221 }
222
223 [Test]
224 public void TestStopOnLongSingleStatementWhileLoop()
225 {
226 TestHelpers.InMethod();
227// TestHelpers.EnableLogging();
228
229 string script =
230@"default
231{
232 state_entry()
233 {
234 integer i = 0;
235 llSay(0, ""Thin Lizzy"");
236
237 while (1 == 1)
238 llSay(0, ""Iter "" + (string)i++);
239 }
240}";
241
242 TestStop(script);
243 }
244
245 [Test]
246 public void TestStopOnLongCompoundStatementWhileLoop()
247 {
248 TestHelpers.InMethod();
249// TestHelpers.EnableLogging();
250
251 string script =
252@"default
253{
254 state_entry()
255 {
256 integer i = 0;
257 llSay(0, ""Thin Lizzy"");
258
259 while (1 == 1)
260 {
261 llSay(0, ""Iter "" + (string)i++);
262 }
263 }
264}";
265
266 TestStop(script);
267 }
268
269 [Test]
270 public void TestNoStopOnSingleStatementDoWhileLoop()
271 {
272 TestHelpers.InMethod();
273// TestHelpers.EnableLogging();
274
275 string script =
276@"default
277{
278 state_entry()
279 {
280 integer i = 0;
281
282 do llSay(0, ""Iter "" + (string)i++);
283 while (i < 2);
284 }
285}";
286
287 TestSingleStatementNoStop(script);
288 }
289
290 [Test]
291 public void TestStopOnLongSingleStatementDoWhileLoop()
292 {
293 TestHelpers.InMethod();
294// TestHelpers.EnableLogging();
295
296 string script =
297@"default
298{
299 state_entry()
300 {
301 integer i = 0;
302 llSay(0, ""Thin Lizzy"");
303
304 do llSay(0, ""Iter "" + (string)i++);
305 while (1 == 1);
306 }
307}";
308
309 TestStop(script);
310 }
311
312 [Test]
313 public void TestStopOnLongCompoundStatementDoWhileLoop()
314 {
315 TestHelpers.InMethod();
316// TestHelpers.EnableLogging();
317
318 string script =
319@"default
320{
321 state_entry()
322 {
323 integer i = 0;
324 llSay(0, ""Thin Lizzy"");
325
326 do
327 {
328 llSay(0, ""Iter "" + (string)i++);
329 } while (1 == 1);
330 }
331}";
332
333 TestStop(script);
334 }
335
336 [Test]
337 public void TestStopOnInfiniteJumpLoop()
338 {
339 TestHelpers.InMethod();
340// TestHelpers.EnableLogging();
341
342 string script =
343@"default
344{
345 state_entry()
346 {
347 integer i = 0;
348 llSay(0, ""Thin Lizzy"");
349
350 @p1;
351 llSay(0, ""Iter "" + (string)i++);
352 jump p1;
353 }
354}";
355
356 TestStop(script);
357 }
358
359 // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before
360 // termination can even be tried.
361// [Test]
362 public void TestStopOnInfiniteUserFunctionCallLoop()
363 {
364 TestHelpers.InMethod();
365// TestHelpers.EnableLogging();
366
367 string script =
368@"
369integer i = 0;
370
371ufn1()
372{
373 llSay(0, ""Iter ufn1() "" + (string)i++);
374 ufn1();
375}
376
377default
378{
379 state_entry()
380 {
381 integer i = 0;
382 llSay(0, ""Thin Lizzy"");
383
384 ufn1();
385 }
386}";
387
388 TestStop(script);
389 }
390
391 // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before
392 // termination can even be tried.
393// [Test]
394 public void TestStopOnInfiniteManualEventCallLoop()
395 {
396 TestHelpers.InMethod();
397// TestHelpers.EnableLogging();
398
399 string script =
400@"default
401{
402 state_entry()
403 {
404 integer i = 0;
405 llSay(0, ""Thin Lizzy"");
406
407 llSay(0, ""Iter"" + (string)i++);
408 default_event_state_entry();
409 }
410}";
411
412 TestStop(script);
413 }
414
415 private SceneObjectPart CreateScript(string script, string itemName, UUID userId)
416 {
417// UUID objectId = TestHelpers.ParseTail(0x100);
418// UUID itemId = TestHelpers.ParseTail(0x3);
419
420 SceneObjectGroup so
421 = SceneHelpers.CreateSceneObject(1, userId, string.Format("Object for {0}", itemName), 0x100);
422 m_scene.AddNewSceneObject(so, true);
423
424 InventoryItemBase itemTemplate = new InventoryItemBase();
425// itemTemplate.ID = itemId;
426 itemTemplate.Name = itemName;
427 itemTemplate.Folder = so.UUID;
428 itemTemplate.InvType = (int)InventoryType.LSL;
429
430 m_scene.EventManager.OnChatFromWorld += OnChatFromWorld;
431
432 return m_scene.RezNewScript(userId, itemTemplate, script);
433 }
434
435 private void TestSingleStatementNoStop(string script)
436 {
437 // In these tests we expect to see at least 2 chat messages to confirm that the loop is working properly.
438 m_chatMessagesThreshold = 2;
439
440 UUID userId = TestHelpers.ParseTail(0x1);
441// UUID objectId = TestHelpers.ParseTail(0x100);
442// UUID itemId = TestHelpers.ParseTail(0x3);
443 string itemName = "TestNoStop";
444
445 SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId);
446
447 // Wait for the script to start the event before we try stopping it.
448 m_chatEvent.WaitOne(60000);
449
450 if (m_osChatMessageReceived == null)
451 Assert.Fail("Script did not start");
452 else
453 Assert.That(m_chatMessagesReceived, Is.EqualTo(2));
454
455 bool running;
456 TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
457 Assert.That(
458 SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True);
459 Assert.That(running, Is.True);
460 }
461
462 private void TestStop(string script)
463 {
464 // In these tests we're only interested in the first message to confirm that the script has started.
465 m_chatMessagesThreshold = 1;
466
467 UUID userId = TestHelpers.ParseTail(0x1);
468// UUID objectId = TestHelpers.ParseTail(0x100);
469// UUID itemId = TestHelpers.ParseTail(0x3);
470 string itemName = "TestStop";
471
472 SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId);
473 TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
474
475 // Wait for the script to start the event before we try stopping it.
476 m_chatEvent.WaitOne(60000);
477
478 if (m_osChatMessageReceived != null)
479 Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message);
480 else
481 Assert.Fail("Script did not start");
482
483 // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script
484 // executes llSay() but has not started the next statement before we try to stop it.
485 Thread.Sleep(1000);
486
487 // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually
488 // stopped. This kind of multi-threading is far from ideal in a regression test.
489 new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start();
490
491 if (!m_stoppedEvent.WaitOne(30000))
492 Assert.Fail("Script did not co-operatively stop.");
493
494 bool running;
495 TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
496 Assert.That(
497 SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True);
498 Assert.That(running, Is.False);
499 }
500
501 private void OnChatFromWorld(object sender, OSChatMessage oscm)
502 {
503 Console.WriteLine("Got chat [{0}]", oscm.Message);
504 m_osChatMessageReceived = oscm;
505
506 if (++m_chatMessagesReceived >= m_chatMessagesThreshold)
507 {
508 m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
509 m_chatEvent.Set();
510 }
511 }
512 }
513} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index c9c4753..b524a18 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -512,7 +512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared
512 else if (o is LSL_Types.LSLFloat) 512 else if (o is LSL_Types.LSLFloat)
513 size += 8; 513 size += 8;
514 else if (o is LSL_Types.LSLString) 514 else if (o is LSL_Types.LSLString)
515 size += ((LSL_Types.LSLString)o).m_string.Length; 515 size += ((LSL_Types.LSLString)o).m_string == null ? 0 : ((LSL_Types.LSLString)o).m_string.Length;
516 else if (o is LSL_Types.key) 516 else if (o is LSL_Types.key)
517 size += ((LSL_Types.key)o).value.Length; 517 size += ((LSL_Types.key)o).value.Length;
518 else if (o is LSL_Types.Vector3) 518 else if (o is LSL_Types.Vector3)
@@ -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/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs
index e6e8777..d08b0a6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs
new file mode 100644
index 0000000..ab44e38
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs
@@ -0,0 +1,249 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using log4net;
35using Nini.Config;
36using NUnit.Framework;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.CoreModules.Scripting.LSLHttp;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.ScriptEngine.Shared;
44using OpenSim.Region.ScriptEngine.Shared.Api;
45using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
46using OpenSim.Services.Interfaces;
47using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock;
49
50namespace OpenSim.Region.ScriptEngine.Shared.Tests
51{
52 /// <summary>
53 /// Tests for HTTP related functions in LSL
54 /// </summary>
55 [TestFixture]
56 public class LSL_ApiHttpTests : OpenSimTestCase
57 {
58 private Scene m_scene;
59 private MockScriptEngine m_engine;
60 private UrlModule m_urlModule;
61
62 private TaskInventoryItem m_scriptItem;
63 private LSL_Api m_lslApi;
64
65 [TestFixtureSetUp]
66 public void TestFixtureSetUp()
67 {
68 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
69 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
70 }
71
72 [TestFixtureTearDown]
73 public void TestFixureTearDown()
74 {
75 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
76 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
77 // tests really shouldn't).
78 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
79 }
80
81 [SetUp]
82 public override void SetUp()
83 {
84 base.SetUp();
85
86 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
87 // variables and the VM is not restarted between tests.
88 uint port = 9999;
89 MainServer.RemoveHttpServer(port);
90
91 BaseHttpServer server = new BaseHttpServer(port, false, 0, "");
92 MainServer.AddHttpServer(server);
93 MainServer.Instance = server;
94
95 server.Start();
96
97 m_engine = new MockScriptEngine();
98 m_urlModule = new UrlModule();
99
100 m_scene = new SceneHelpers().SetupScene();
101 SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine, m_urlModule);
102
103 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
104 m_scriptItem = TaskInventoryHelpers.AddScript(m_scene, so.RootPart);
105
106 // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm.
107 // Possibly this could be done and we could obtain it directly from the MockScriptEngine.
108 m_lslApi = new LSL_Api();
109 m_lslApi.Initialize(m_engine, so.RootPart, m_scriptItem, null);
110 }
111
112 [TearDown]
113 public void TearDown()
114 {
115 MainServer.Instance.Stop();
116 }
117
118 [Test]
119 public void TestLlReleaseUrl()
120 {
121 TestHelpers.InMethod();
122
123 m_lslApi.llRequestURL();
124 string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString();
125
126 {
127 // Check that the initial number of URLs is correct
128 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
129 }
130
131 {
132 // Check releasing a non-url
133 m_lslApi.llReleaseURL("GARBAGE");
134 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
135 }
136
137 {
138 // Check releasing a non-existing url
139 m_lslApi.llReleaseURL("http://example.com");
140 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
141 }
142
143 {
144 // Check URL release
145 m_lslApi.llReleaseURL(returnedUri);
146 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls));
147
148 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
149
150 bool gotExpectedException = false;
151
152 try
153 {
154 using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
155 {}
156 }
157 catch (WebException e)
158 {
159 using (HttpWebResponse response = (HttpWebResponse)e.Response)
160 gotExpectedException = response.StatusCode == HttpStatusCode.NotFound;
161 }
162
163 Assert.That(gotExpectedException, Is.True);
164 }
165
166 {
167 // Check releasing the same URL again
168 m_lslApi.llReleaseURL(returnedUri);
169 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls));
170 }
171 }
172
173 [Test]
174 public void TestLlRequestUrl()
175 {
176 TestHelpers.InMethod();
177
178 string requestId = m_lslApi.llRequestURL();
179 Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString()));
180 string returnedUri;
181
182 {
183 // Check that URL is correctly set up
184 Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
185
186 Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID));
187
188 List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID];
189 Assert.That(events.Count, Is.EqualTo(1));
190 EventParams eventParams = events[0];
191 Assert.That(eventParams.EventName, Is.EqualTo("http_request"));
192
193 UUID returnKey;
194 string rawReturnKey = eventParams.Params[0].ToString();
195 string method = eventParams.Params[1].ToString();
196 returnedUri = eventParams.Params[2].ToString();
197
198 Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True);
199 Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED));
200 Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True);
201 }
202
203 {
204 // Check that request to URL works.
205 string testResponse = "Hello World";
206
207 m_engine.ClearPostedEvents();
208 m_engine.PostEventHook
209 += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
210
211// Console.WriteLine("Trying {0}", returnedUri);
212
213 AssertHttpResponse(returnedUri, testResponse);
214
215 Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID));
216
217 List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID];
218 Assert.That(events.Count, Is.EqualTo(1));
219 EventParams eventParams = events[0];
220 Assert.That(eventParams.EventName, Is.EqualTo("http_request"));
221
222 UUID returnKey;
223 string rawReturnKey = eventParams.Params[0].ToString();
224 string method = eventParams.Params[1].ToString();
225 string body = eventParams.Params[2].ToString();
226
227 Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True);
228 Assert.That(method, Is.EqualTo("GET"));
229 Assert.That(body, Is.EqualTo(""));
230 }
231 }
232
233 private void AssertHttpResponse(string uri, string expectedResponse)
234 {
235 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
236
237 using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
238 {
239 using (Stream stream = webResponse.GetResponseStream())
240 {
241 using (StreamReader reader = new StreamReader(stream))
242 {
243 Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse));
244 }
245 }
246 }
247 }
248 }
249} \ No newline at end of file
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..ac9f93b 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");
@@ -90,7 +93,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
90 // FIXME: This should really be a script item (with accompanying script) 93 // FIXME: This should really be a script item (with accompanying script)
91 TaskInventoryItem grp1Item 94 TaskInventoryItem grp1Item
92 = TaskInventoryHelpers.AddNotecard( 95 = TaskInventoryHelpers.AddNotecard(
93 m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 96 m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
94 grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 97 grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
95 98
96 SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); 99 SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20);
@@ -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
@@ -124,12 +127,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
124 // FIXME: This should really be a script item (with accompanying script) 127 // FIXME: This should really be a script item (with accompanying script)
125 TaskInventoryItem grp1Item 128 TaskInventoryItem grp1Item
126 = TaskInventoryHelpers.AddNotecard( 129 = TaskInventoryHelpers.AddNotecard(
127 m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 130 m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
128 131
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_ApiNotecardTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs
new file mode 100644
index 0000000..c92bcdb
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs
@@ -0,0 +1,270 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using System.Reflection;
6using System.Text;
7using log4net;
8using Nini.Config;
9using NUnit.Framework;
10using OpenMetaverse;
11using OpenSim.Framework;
12using OpenSim.Framework.Servers;
13using OpenSim.Framework.Servers.HttpServer;
14using OpenSim.Region.CoreModules.Scripting.LSLHttp;
15using OpenSim.Region.Framework.Scenes;
16using OpenSim.Region.ScriptEngine.Shared;
17using OpenSim.Region.ScriptEngine.Shared.Api;
18using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
19using OpenSim.Services.Interfaces;
20using OpenSim.Tests.Common;
21using OpenSim.Tests.Common.Mock;
22
23namespace OpenSim.Region.ScriptEngine.Shared.Tests
24{
25 /// <summary>
26 /// Tests for notecard related functions in LSL
27 /// </summary>
28 [TestFixture]
29 public class LSL_ApiNotecardTests : OpenSimTestCase
30 {
31 private Scene m_scene;
32 private MockScriptEngine m_engine;
33
34 private SceneObjectGroup m_so;
35 private TaskInventoryItem m_scriptItem;
36 private LSL_Api m_lslApi;
37
38 [TestFixtureSetUp]
39 public void TestFixtureSetUp()
40 {
41 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
42 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
43 }
44
45 [TestFixtureTearDown]
46 public void TestFixureTearDown()
47 {
48 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
49 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
50 // tests really shouldn't).
51 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
52 }
53
54 [SetUp]
55 public override void SetUp()
56 {
57 base.SetUp();
58
59 m_engine = new MockScriptEngine();
60
61 m_scene = new SceneHelpers().SetupScene();
62 SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine);
63
64 m_so = SceneHelpers.AddSceneObject(m_scene);
65 m_scriptItem = TaskInventoryHelpers.AddScript(m_scene, m_so.RootPart);
66
67 // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm.
68 // Possibly this could be done and we could obtain it directly from the MockScriptEngine.
69 m_lslApi = new LSL_Api();
70 m_lslApi.Initialize(m_engine, m_so.RootPart, m_scriptItem, null);
71 }
72
73 [Test]
74 public void TestLlGetNotecardLine()
75 {
76 TestHelpers.InMethod();
77
78 string[] ncLines = { "One", "Two", "Three" };
79
80 TaskInventoryItem ncItem
81 = TaskInventoryHelpers.AddNotecard(m_scene, m_so.RootPart, "nc", "1", "10", string.Join("\n", ncLines));
82
83 AssertValidNotecardLine(ncItem.Name, 0, ncLines[0]);
84 AssertValidNotecardLine(ncItem.Name, 2, ncLines[2]);
85 AssertValidNotecardLine(ncItem.Name, 3, ScriptBaseClass.EOF);
86 AssertValidNotecardLine(ncItem.Name, 4, ScriptBaseClass.EOF);
87
88 // XXX: Is this correct or do we really expect no dataserver event to fire at all?
89 AssertValidNotecardLine(ncItem.Name, -1, "");
90 AssertValidNotecardLine(ncItem.Name, -2, "");
91 }
92
93 [Test]
94 public void TestLlGetNotecardLine_NoNotecard()
95 {
96 TestHelpers.InMethod();
97
98 AssertInValidNotecardLine("nc", 0);
99 }
100
101 [Test]
102 public void TestLlGetNotecardLine_NotANotecard()
103 {
104 TestHelpers.InMethod();
105
106 TaskInventoryItem ncItem = TaskInventoryHelpers.AddScript(m_scene, m_so.RootPart, "nc1", "Not important");
107
108 AssertInValidNotecardLine(ncItem.Name, 0);
109 }
110
111 private void AssertValidNotecardLine(string ncName, int lineNumber, string assertLine)
112 {
113 string key = m_lslApi.llGetNotecardLine(ncName, lineNumber);
114 Assert.That(key, Is.Not.EqualTo(UUID.Zero.ToString()));
115
116 Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(1));
117 Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID));
118
119 List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID];
120 Assert.That(events.Count, Is.EqualTo(1));
121 EventParams eventParams = events[0];
122
123 Assert.That(eventParams.EventName, Is.EqualTo("dataserver"));
124 Assert.That(eventParams.Params[0].ToString(), Is.EqualTo(key));
125 Assert.That(eventParams.Params[1].ToString(), Is.EqualTo(assertLine));
126
127 m_engine.ClearPostedEvents();
128 }
129
130 private void AssertInValidNotecardLine(string ncName, int lineNumber)
131 {
132 string key = m_lslApi.llGetNotecardLine(ncName, lineNumber);
133 Assert.That(key, Is.EqualTo(UUID.Zero.ToString()));
134
135 Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(0));
136 }
137
138// [Test]
139// public void TestLlReleaseUrl()
140// {
141// TestHelpers.InMethod();
142//
143// m_lslApi.llRequestURL();
144// string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString();
145//
146// {
147// // Check that the initial number of URLs is correct
148// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
149// }
150//
151// {
152// // Check releasing a non-url
153// m_lslApi.llReleaseURL("GARBAGE");
154// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
155// }
156//
157// {
158// // Check releasing a non-existing url
159// m_lslApi.llReleaseURL("http://example.com");
160// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
161// }
162//
163// {
164// // Check URL release
165// m_lslApi.llReleaseURL(returnedUri);
166// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls));
167//
168// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
169//
170// bool gotExpectedException = false;
171//
172// try
173// {
174// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
175// {}
176// }
177// catch (WebException e)
178// {
179// using (HttpWebResponse response = (HttpWebResponse)e.Response)
180// gotExpectedException = response.StatusCode == HttpStatusCode.NotFound;
181// }
182//
183// Assert.That(gotExpectedException, Is.True);
184// }
185//
186// {
187// // Check releasing the same URL again
188// m_lslApi.llReleaseURL(returnedUri);
189// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls));
190// }
191// }
192//
193// [Test]
194// public void TestLlRequestUrl()
195// {
196// TestHelpers.InMethod();
197//
198// string requestId = m_lslApi.llRequestURL();
199// Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString()));
200// string returnedUri;
201//
202// {
203// // Check that URL is correctly set up
204// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1));
205//
206// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID));
207//
208// List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID];
209// Assert.That(events.Count, Is.EqualTo(1));
210// EventParams eventParams = events[0];
211// Assert.That(eventParams.EventName, Is.EqualTo("http_request"));
212//
213// UUID returnKey;
214// string rawReturnKey = eventParams.Params[0].ToString();
215// string method = eventParams.Params[1].ToString();
216// returnedUri = eventParams.Params[2].ToString();
217//
218// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True);
219// Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED));
220// Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True);
221// }
222//
223// {
224// // Check that request to URL works.
225// string testResponse = "Hello World";
226//
227// m_engine.ClearPostedEvents();
228// m_engine.PostEventHook
229// += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
230//
231//// Console.WriteLine("Trying {0}", returnedUri);
232// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
233//
234// AssertHttpResponse(returnedUri, testResponse);
235//
236// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID));
237//
238// List<EventParams> events = m_engine.PostedEvents[m_scriptItem.ItemID];
239// Assert.That(events.Count, Is.EqualTo(1));
240// EventParams eventParams = events[0];
241// Assert.That(eventParams.EventName, Is.EqualTo("http_request"));
242//
243// UUID returnKey;
244// string rawReturnKey = eventParams.Params[0].ToString();
245// string method = eventParams.Params[1].ToString();
246// string body = eventParams.Params[2].ToString();
247//
248// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True);
249// Assert.That(method, Is.EqualTo("GET"));
250// Assert.That(body, Is.EqualTo(""));
251// }
252// }
253//
254// private void AssertHttpResponse(string uri, string expectedResponse)
255// {
256// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
257//
258// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
259// {
260// using (Stream stream = webResponse.GetResponseStream())
261// {
262// using (StreamReader reader = new StreamReader(stream))
263// {
264// Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse));
265// }
266// }
267// }
268// }
269 }
270} \ No newline at end of file
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..e422f5b 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,13 +145,13 @@ 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(
153 m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900)); 154 m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900), "Hello World!");
154 155
155 bool exceptionCaught = false; 156 bool exceptionCaught = false;
156 157
@@ -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..74f010e 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
@@ -223,7 +222,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
223 // Store an avatar with a different height from default in a notecard. 222 // Store an avatar with a different height from default in a notecard.
224 UUID userId = TestHelpers.ParseTail(0x1); 223 UUID userId = TestHelpers.ParseTail(0x1);
225 float firstHeight = 1.9f; 224 float firstHeight = 1.9f;
226 float secondHeight = 2.1f; 225// float secondHeight = 2.1f;
227 string firstAppearanceNcName = "appearanceNc1"; 226 string firstAppearanceNcName = "appearanceNc1";
228 string secondAppearanceNcName = "appearanceNc2"; 227 string secondAppearanceNcName = "appearanceNc2";
229 228
@@ -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/Api/Runtime/XEngineScriptBase.cs b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs
new file mode 100644
index 0000000..f4211c8
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs
@@ -0,0 +1,61 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Runtime.Remoting;
30using System.Runtime.Remoting.Lifetime;
31using System.Security.Permissions;
32using System.Threading;
33using System.Reflection;
34using System.Collections;
35using System.Collections.Generic;
36using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
39
40namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase
41{
42 public class XEngineScriptBase : ScriptBaseClass
43 {
44 /// <summary>
45 /// Used for script sleeps when we are using co-operative script termination.
46 /// </summary>
47 /// <remarks>null if co-operative script termination is not active</remarks>
48 WaitHandle m_coopSleepHandle;
49
50 public XEngineScriptBase(WaitHandle coopSleepHandle) : base()
51 {
52 m_coopSleepHandle = coopSleepHandle;
53 }
54
55 public void opensim_reserved_CheckForCoopTermination()
56 {
57 if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0))
58 throw new ScriptCoopStopException();
59 }
60 }
61} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
index 9405075..0ff2da3 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
@@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
52 { 52 {
53 myScriptEngine = _ScriptEngine; 53 myScriptEngine = _ScriptEngine;
54 54
55 m_log.Info("[XEngine] Hooking up to server events"); 55// m_log.Info("[XEngine] Hooking up to server events");
56 myScriptEngine.World.EventManager.OnAttach += attach; 56 myScriptEngine.World.EventManager.OnAttach += attach;
57 myScriptEngine.World.EventManager.OnObjectGrab += touch_start; 57 myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
58 myScriptEngine.World.EventManager.OnObjectGrabbing += touch; 58 myScriptEngine.World.EventManager.OnObjectGrabbing += touch;
@@ -62,6 +62,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
62 myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; 62 myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
63 myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target; 63 myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target;
64 myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target; 64 myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target;
65 myScriptEngine.World.EventManager.OnScriptMovingStartEvent += moving_start;
66 myScriptEngine.World.EventManager.OnScriptMovingEndEvent += moving_end;
65 myScriptEngine.World.EventManager.OnScriptControlEvent += control; 67 myScriptEngine.World.EventManager.OnScriptControlEvent += control;
66 myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; 68 myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start;
67 myScriptEngine.World.EventManager.OnScriptColliding += collision; 69 myScriptEngine.World.EventManager.OnScriptColliding += collision;
@@ -69,7 +71,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
69 myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; 71 myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start;
70 myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; 72 myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision;
71 myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; 73 myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
72 IMoneyModule money=myScriptEngine.World.RequestModuleInterface<IMoneyModule>(); 74 IMoneyModule money = myScriptEngine.World.RequestModuleInterface<IMoneyModule>();
73 if (money != null) 75 if (money != null)
74 { 76 {
75 money.OnObjectPaid+=HandleObjectPaid; 77 money.OnObjectPaid+=HandleObjectPaid;
@@ -419,14 +421,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
419 // dataserver: not handled here 421 // dataserver: not handled here
420 // link_message: not handled here 422 // link_message: not handled here
421 423
422 public void moving_start(uint localID, UUID itemID) 424 public void moving_start(uint localID)
423 { 425 {
424 myScriptEngine.PostObjectEvent(localID, new EventParams( 426 myScriptEngine.PostObjectEvent(localID, new EventParams(
425 "moving_start",new object[0], 427 "moving_start",new object[0],
426 new DetectParams[0])); 428 new DetectParams[0]));
427 } 429 }
428 430
429 public void moving_end(uint localID, UUID itemID) 431 public void moving_end(uint localID)
430 { 432 {
431 myScriptEngine.PostObjectEvent(localID, new EventParams( 433 myScriptEngine.PostObjectEvent(localID, new EventParams(
432 "moving_end",new object[0], 434 "moving_end",new object[0],
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
index bd26a8b..f0640da 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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/XEngineBasicTests.cs
index f331658..5abfe9a 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.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..17243ab 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;
@@ -46,13 +47,14 @@ using OpenSim.Framework;
46using OpenSim.Framework.Console; 47using OpenSim.Framework.Console;
47using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Interfaces; 49using OpenSim.Region.Framework.Interfaces;
50using OpenSim.Region.ScriptEngine.Interfaces;
49using OpenSim.Region.ScriptEngine.Shared; 51using OpenSim.Region.ScriptEngine.Shared;
50using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
51using OpenSim.Region.ScriptEngine.Shared.CodeTools; 52using OpenSim.Region.ScriptEngine.Shared.CodeTools;
52using OpenSim.Region.ScriptEngine.Shared.Instance; 53using OpenSim.Region.ScriptEngine.Shared.Instance;
53using OpenSim.Region.ScriptEngine.Shared.Api; 54using OpenSim.Region.ScriptEngine.Shared.Api;
54using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 55using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
55using OpenSim.Region.ScriptEngine.Interfaces; 56using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
57using OpenSim.Region.ScriptEngine.XEngine.ScriptBase;
56using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; 58using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
57 59
58using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>; 60using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
@@ -107,6 +109,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
107 private IXmlRpcRouter m_XmlRpcRouter; 109 private IXmlRpcRouter m_XmlRpcRouter;
108 private int m_EventLimit; 110 private int m_EventLimit;
109 private bool m_KillTimedOutScripts; 111 private bool m_KillTimedOutScripts;
112
113 /// <summary>
114 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
115 /// its thread.
116 /// </summary>
117 /// <remarks>
118 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
119 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
120 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
121 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
122 /// actually hold.
123 ///
124 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
125 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
126 /// shutting down.
127 /// </remarks>
128 private int m_WaitForEventCompletionOnScriptStop = 1000;
129
110 private string m_ScriptEnginesPath = null; 130 private string m_ScriptEnginesPath = null;
111 131
112 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); 132 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
@@ -218,11 +238,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
218 } 238 }
219 } 239 }
220 240
241 private ScriptEngineConsoleCommands m_consoleCommands;
242
221 public string ScriptEngineName 243 public string ScriptEngineName
222 { 244 {
223 get { return "XEngine"; } 245 get { return "XEngine"; }
224 } 246 }
225 247
248 public string ScriptClassName { get; private set; }
249
250 public string ScriptBaseClassName { get; private set; }
251
252 public ParameterInfo[] ScriptBaseClassParameters { get; private set; }
253
254 public string[] ScriptReferencedAssemblies { get; private set; }
255
226 public Scene World 256 public Scene World
227 { 257 {
228 get { return m_Scene; } 258 get { return m_Scene; }
@@ -277,21 +307,35 @@ namespace OpenSim.Region.ScriptEngine.XEngine
277 307
278 m_ScriptConfig = configSource.Configs["XEngine"]; 308 m_ScriptConfig = configSource.Configs["XEngine"];
279 m_ConfigSource = configSource; 309 m_ConfigSource = configSource;
310
311 string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort");
312
313 m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy);
314
315 if (rawScriptStopStrategy == "co-op")
316 {
317 ScriptClassName = "XEngineScript";
318 ScriptBaseClassName = typeof(XEngineScriptBase).FullName;
319 ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters();
320 ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) };
321 }
322 else
323 {
324 ScriptClassName = "Script";
325 ScriptBaseClassName = typeof(ScriptBaseClass).FullName;
326 }
327
328// Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]);
280 } 329 }
281 330
282 public void AddRegion(Scene scene) 331 public void AddRegion(Scene scene)
283 { 332 {
284 if (m_ScriptConfig == null) 333 if (m_ScriptConfig == null)
285 return; 334 return;
335
286 m_ScriptFailCount = 0; 336 m_ScriptFailCount = 0;
287 m_ScriptErrorMessage = String.Empty; 337 m_ScriptErrorMessage = String.Empty;
288 338
289 if (m_ScriptConfig == null)
290 {
291// m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled");
292 return;
293 }
294
295 m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); 339 m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true);
296 340
297 if (!m_Enabled) 341 if (!m_Enabled)
@@ -316,6 +360,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
316 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 360 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
317 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 361 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
318 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; 362 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
363 m_WaitForEventCompletionOnScriptStop
364 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
365
319 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); 366 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
320 367
321 m_Prio = ThreadPriority.BelowNormal; 368 m_Prio = ThreadPriority.BelowNormal;
@@ -364,48 +411,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine
364 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved; 411 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
365 } 412 }
366 413
414 m_consoleCommands = new ScriptEngineConsoleCommands(this);
415 m_consoleCommands.RegisterCommands();
416
367 MainConsole.Instance.Commands.AddCommand( 417 MainConsole.Instance.Commands.AddCommand(
368 "Scripts", false, "xengine status", "xengine status", "Show status information", 418 "Scripts", false, "xengine status", "xengine status", "Show status information",
369 "Show status information on the script engine.", 419 "Show status information on the script engine.",
370 HandleShowStatus); 420 HandleShowStatus);
371 421
372 MainConsole.Instance.Commands.AddCommand( 422 MainConsole.Instance.Commands.AddCommand(
373 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", 423 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
374 "Show information on all scripts known to the script engine." 424 "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.", 425 + "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
376 HandleShowScripts); 426 HandleShowScripts);
377 427
378 MainConsole.Instance.Commands.AddCommand( 428 MainConsole.Instance.Commands.AddCommand(
379 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>]", "Show script information", 429 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
380 "Synonym for scripts show command", HandleShowScripts); 430 "Synonym for scripts show command", HandleShowScripts);
381 431
382 MainConsole.Instance.Commands.AddCommand( 432 MainConsole.Instance.Commands.AddCommand(
383 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>]", "Suspends all running scripts", 433 "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" 434 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
385 + " script that is currently processing an event.\n" 435 + " script that is currently processing an event.\n"
386 + "Suspended scripts will continue to accumulate events but won't process them.\n" 436 + "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.", 437 + "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)); 438 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
389 439
390 MainConsole.Instance.Commands.AddCommand( 440 MainConsole.Instance.Commands.AddCommand(
391 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", 441 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
392 "Resumes all currently suspended scripts.\n" 442 "Resumes all currently suspended scripts.\n"
393 + "Resumed scripts will process all events accumulated whilst suspended." 443 + "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.", 444 + "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)); 445 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
396 446
397 MainConsole.Instance.Commands.AddCommand( 447 MainConsole.Instance.Commands.AddCommand(
398 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", 448 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
399 "Stops all running scripts." 449 "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.", 450 + "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)); 451 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
402 452
403 MainConsole.Instance.Commands.AddCommand( 453 MainConsole.Instance.Commands.AddCommand(
404 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", 454 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
405 "Starts all stopped scripts." 455 "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.", 456 + "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)); 457 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
408 458
459 MainConsole.Instance.Commands.AddCommand(
460 "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
461 "Activates or deactivates extra debug logging for the given script.\n"
462 + "Level == 0, deactivate extra debug logging.\n"
463 + "Level >= 1, log state changes.\n"
464 + "Level >= 2, log event invocations.\n",
465 HandleDebugScriptLogCommand);
466
409// MainConsole.Instance.Commands.AddCommand( 467// MainConsole.Instance.Commands.AddCommand(
410// "Debug", false, "debug xengine", "debug xengine [<level>]", 468// "Debug", false, "debug xengine", "debug xengine [<level>]",
411// "Turn on detailed xengine debugging.", 469// "Turn on detailed xengine debugging.",
@@ -414,6 +472,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
414// HandleDebugLevelCommand); 472// HandleDebugLevelCommand);
415 } 473 }
416 474
475 private void HandleDebugScriptLogCommand(string module, string[] args)
476 {
477 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
478 return;
479
480 if (args.Length != 5)
481 {
482 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
483 return;
484 }
485
486 UUID itemId;
487
488 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
489 return;
490
491 int newLevel;
492
493 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
494 return;
495
496 IScriptInstance si;
497
498 lock (m_Scripts)
499 {
500 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
501 // engine
502 if (!m_Scripts.TryGetValue(itemId, out si))
503 return;
504 }
505
506 si.DebugLevel = newLevel;
507 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
508 }
509
417 /// <summary> 510 /// <summary>
418 /// Change debug level 511 /// Change debug level
419 /// </summary> 512 /// </summary>
@@ -445,9 +538,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
445 /// </summary> 538 /// </summary>
446 /// <param name="cmdparams"></param> 539 /// <param name="cmdparams"></param>
447 /// <param name="instance"></param> 540 /// <param name="instance"></param>
448 /// <returns>true if we're okay to proceed, false if not.</returns> 541 /// <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) 542 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
450 { 543 {
544 HandleScriptsAction<object>(cmdparams, action, null);
545 }
546
547 /// <summary>
548 /// Parse the raw item id into a script instance from the command params if it's present.
549 /// </summary>
550 /// <param name="cmdparams"></param>
551 /// <param name="instance"></param>
552 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
553 private void HandleScriptsAction<TKey>(
554 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
555 {
451 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 556 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
452 return; 557 return;
453 558
@@ -458,35 +563,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine
458 563
459 if (cmdparams.Length == 2) 564 if (cmdparams.Length == 2)
460 { 565 {
461 foreach (IScriptInstance instance in m_Scripts.Values) 566 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
567
568 if (keySelector != null)
569 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
570
571 foreach (IScriptInstance instance in scripts)
462 action(instance); 572 action(instance);
463 573
464 return; 574 return;
465 } 575 }
466 576
467 rawItemId = cmdparams[2]; 577 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 { 578 {
477 IScriptInstance instance = GetInstance(itemId); 579 rawItemId = cmdparams[i];
478 if (instance == null) 580
581 if (!UUID.TryParse(rawItemId, out itemId))
479 { 582 {
480 // Commented out for now since this will cause false reports on simulators with more than 583 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 584 continue;
482 // go to both regions... (sigh)
483// MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
484 return;
485 } 585 }
486 else 586
587 if (itemId != UUID.Zero)
487 { 588 {
488 action(instance); 589 IScriptInstance instance = GetInstance(itemId);
489 return; 590 if (instance == null)
591 {
592 // Commented out for now since this will cause false reports on simulators with more than
593 // one scene where the current command line set region is 'root' (which causes commands to
594 // go to both regions... (sigh)
595 // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
596 continue;
597 }
598 else
599 {
600 action(instance);
601 }
490 } 602 }
491 } 603 }
492 } 604 }
@@ -505,9 +617,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
505 StringBuilder sb = new StringBuilder(); 617 StringBuilder sb = new StringBuilder();
506 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); 618 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
507 619
620 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
621
508 lock (m_Scripts) 622 lock (m_Scripts)
509 sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); 623 {
624 scriptsLoaded = m_Scripts.Count;
510 625
626 foreach (IScriptInstance si in m_Scripts.Values)
627 {
628 eventsQueued += si.EventsQueued;
629 eventsProcessed += si.EventsProcessed;
630 }
631 }
632
633 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
511 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); 634 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
512 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); 635 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
513 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); 636 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@@ -516,6 +639,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
516 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); 639 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
517 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); 640 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
518// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); 641// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
642 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
643 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
519 644
520 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); 645 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
521 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); 646 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@@ -546,7 +671,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
546 } 671 }
547 } 672 }
548 673
549 HandleScriptsAction(cmdparams, HandleShowScript); 674 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
550 } 675 }
551 676
552 private void HandleShowScript(IScriptInstance instance) 677 private void HandleShowScript(IScriptInstance instance)
@@ -572,15 +697,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine
572 } 697 }
573 698
574 StringBuilder sb = new StringBuilder(); 699 StringBuilder sb = new StringBuilder();
575 Queue eq = instance.EventQueue;
576 700
577 sb.AppendFormat("Script name : {0}\n", instance.ScriptName); 701 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
578 sb.AppendFormat("Status : {0}\n", status); 702 sb.AppendFormat("Status : {0}\n", status);
579 703 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
580 lock (eq) 704 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); 705 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
706 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
584 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 707 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
585 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 708 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
586 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 709 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@@ -1079,7 +1202,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1079 } 1202 }
1080 1203
1081 m_log.DebugFormat( 1204 m_log.DebugFormat(
1082 "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", 1205 "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1083 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, 1206 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1084 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); 1207 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1085 1208
@@ -1089,8 +1212,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 1212
1090 string assembly = ""; 1213 string assembly = "";
1091 1214
1092 CultureInfo USCulture = new CultureInfo("en-US"); 1215 Culture.SetCurrentCulture();
1093 Thread.CurrentThread.CurrentCulture = USCulture;
1094 1216
1095 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; 1217 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1096 1218
@@ -1101,6 +1223,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1101 lock (m_AddingAssemblies) 1223 lock (m_AddingAssemblies)
1102 { 1224 {
1103 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); 1225 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap);
1226
1104 if (!m_AddingAssemblies.ContainsKey(assembly)) { 1227 if (!m_AddingAssemblies.ContainsKey(assembly)) {
1105 m_AddingAssemblies[assembly] = 1; 1228 m_AddingAssemblies[assembly] = 1;
1106 } else { 1229 } else {
@@ -1150,7 +1273,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1150 } 1273 }
1151 catch (Exception e) 1274 catch (Exception e)
1152 { 1275 {
1153// m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); 1276// m_log.ErrorFormat(
1277// "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}",
1278// itemID, e.Message, e.StackTrace);
1154 1279
1155 // try 1280 // try
1156 // { 1281 // {
@@ -1229,13 +1354,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1229 sandbox = AppDomain.CurrentDomain; 1354 sandbox = AppDomain.CurrentDomain;
1230 } 1355 }
1231 1356
1232 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 1357 if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource))
1233 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 1358 return false;
1234 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
1235 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
1236 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
1237 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
1238 //sandbox.SetAppDomainPolicy(sandboxPolicy);
1239 1359
1240 m_AppDomains[appDomain] = sandbox; 1360 m_AppDomains[appDomain] = sandbox;
1241 1361
@@ -1256,12 +1376,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1256 m_DomainScripts[appDomain].Add(itemID); 1376 m_DomainScripts[appDomain].Add(itemID);
1257 1377
1258 instance = new ScriptInstance(this, part, 1378 instance = new ScriptInstance(this, part,
1259 itemID, assetID, assembly, 1379 item,
1260 m_AppDomains[appDomain], 1380 startParam, postOnRez,
1261 part.ParentGroup.RootPart.Name, 1381 m_MaxScriptQueue);
1262 item.Name, startParam, postOnRez,
1263 stateSource, m_MaxScriptQueue);
1264 1382
1383 instance.Load(m_AppDomains[appDomain], assembly, stateSource);
1265// m_log.DebugFormat( 1384// m_log.DebugFormat(
1266// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", 1385// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
1267// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, 1386// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
@@ -1347,9 +1466,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1347 lockScriptsForWrite(false); 1466 lockScriptsForWrite(false);
1348 instance.ClearQueue(); 1467 instance.ClearQueue();
1349 1468
1350 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1469 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 1470
1354// bool objectRemoved = false; 1471// bool objectRemoved = false;
1355 1472
@@ -1477,7 +1594,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1477 m_MaxScriptQueue = maxScriptQueue; 1594 m_MaxScriptQueue = maxScriptQueue;
1478 1595
1479 STPStartInfo startInfo = new STPStartInfo(); 1596 STPStartInfo startInfo = new STPStartInfo();
1480 startInfo.IdleTimeout = idleTimeout*1000; // convert to seconds as stated in .ini 1597 startInfo.ThreadPoolName = "XEngine";
1598 startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
1481 startInfo.MaxWorkerThreads = maxThreads; 1599 startInfo.MaxWorkerThreads = maxThreads;
1482 startInfo.MinWorkerThreads = minThreads; 1600 startInfo.MinWorkerThreads = minThreads;
1483 startInfo.ThreadPriority = threadPriority;; 1601 startInfo.ThreadPriority = threadPriority;;
@@ -1504,8 +1622,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1504 /// <returns></returns> 1622 /// <returns></returns>
1505 private object ProcessEventHandler(object parms) 1623 private object ProcessEventHandler(object parms)
1506 { 1624 {
1507 CultureInfo USCulture = new CultureInfo("en-US"); 1625 Culture.SetCurrentCulture();
1508 Thread.CurrentThread.CurrentCulture = USCulture;
1509 1626
1510 IScriptInstance instance = (ScriptInstance) parms; 1627 IScriptInstance instance = (ScriptInstance) parms;
1511 1628
@@ -1693,7 +1810,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1693 { 1810 {
1694 IScriptInstance instance = GetInstance(itemID); 1811 IScriptInstance instance = GetInstance(itemID);
1695 if (instance != null) 1812 if (instance != null)
1696 instance.ResetScript(); 1813 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1697 } 1814 }
1698 1815
1699 public void StartScript(UUID itemID) 1816 public void StartScript(UUID itemID)
@@ -1708,14 +1825,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1708 public void StopScript(UUID itemID) 1825 public void StopScript(UUID itemID)
1709 { 1826 {
1710 IScriptInstance instance = GetInstance(itemID); 1827 IScriptInstance instance = GetInstance(itemID);
1828
1711 if (instance != null) 1829 if (instance != null)
1712 { 1830 {
1713 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1831 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 } 1832 }
1717 else 1833 else
1718 { 1834 {
1835// 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); 1836 m_runFlags.AddOrUpdate(itemID, false, 240);
1720 } 1837 }
1721 } 1838 }
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 2ac5c31..8dd7677 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
57 wr.Abort(); 57 wr.Abort();
58 } 58 }
59 59
60 public bool Wait(TimeSpan t) 60 public bool Wait(int t)
61 { 61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3).
62 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); 66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
63 } 67 }
64 } 68 }
diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
index 3243a9a..6a1112c 100644
--- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
+++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
@@ -32,6 +32,7 @@ using System.Reflection;
32using System.Text; 32using System.Text;
33using Mono.Data.SqliteClient; 33using Mono.Data.SqliteClient;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
35using OpenSim.Framework; 36using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring; 38using OpenSim.Framework.Monitoring;
@@ -51,7 +52,6 @@ namespace OpenSim.Region.UserStatistics
51 52
52 public Hashtable ProcessModel(Hashtable pParams) 53 public Hashtable ProcessModel(Hashtable pParams)
53 { 54 {
54
55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; 55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
56 56
57 Hashtable nh = new Hashtable(); 57 Hashtable nh = new Hashtable();
@@ -129,6 +129,86 @@ namespace OpenSim.Region.UserStatistics
129 return output.ToString(); 129 return output.ToString();
130 } 130 }
131 131
132 /// <summary>
133 /// Convert active connections information to JSON string. Returns a structure:
134 /// <pre>
135 /// {"regionName": {
136 /// "presenceName": {
137 /// "name": "presenceName",
138 /// "position": "<x,y,z>",
139 /// "isRoot": "false",
140 /// "throttle": {
141 /// },
142 /// "queue": {
143 /// }
144 /// },
145 /// ... // multiple presences in the scene
146 /// },
147 /// ... // multiple regions in the sim
148 /// }
149 ///
150 /// </pre>
151 /// </summary>
152 /// <param name="pModelResult"></param>
153 /// <returns></returns>
154 public string RenderJson(Hashtable pModelResult)
155 {
156 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
157
158 OSDMap regionInfo = new OSDMap();
159 foreach (Scene scene in all_scenes)
160 {
161 OSDMap sceneInfo = new OpenMetaverse.StructuredData.OSDMap();
162 List<ScenePresence> avatarInScene = scene.GetScenePresences();
163 foreach (ScenePresence av in avatarInScene)
164 {
165 OSDMap presenceInfo = new OSDMap();
166 presenceInfo.Add("Name", new OSDString(av.Name));
167
168 Dictionary<string,string> queues = new Dictionary<string, string>();
169 if (av.ControllingClient is IStatsCollector)
170 {
171 IStatsCollector isClient = (IStatsCollector) av.ControllingClient;
172 queues = decodeQueueReport(isClient.Report());
173 }
174 OSDMap queueInfo = new OpenMetaverse.StructuredData.OSDMap();
175 foreach (KeyValuePair<string, string> kvp in queues) {
176 queueInfo.Add(kvp.Key, new OSDString(kvp.Value));
177 }
178 sceneInfo.Add("queues", queueInfo);
179
180 if (av.IsChildAgent)
181 presenceInfo.Add("isRoot", new OSDString("false"));
182 else
183 presenceInfo.Add("isRoot", new OSDString("true"));
184
185 if (av.AbsolutePosition == DefaultNeighborPosition)
186 {
187 presenceInfo.Add("position", new OSDString("<0, 0, 0>"));
188 }
189 else
190 {
191 presenceInfo.Add("position", new OSDString(string.Format("<{0},{1},{2}>",
192 (int)av.AbsolutePosition.X,
193 (int) av.AbsolutePosition.Y,
194 (int) av.AbsolutePosition.Z)) );
195 }
196
197 Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
198 OSDMap throttleInfo = new OpenMetaverse.StructuredData.OSDMap();
199 foreach (string throttlename in throttles.Keys)
200 {
201 throttleInfo.Add(throttlename, new OSDString(throttles[throttlename].ToString()));
202 }
203 presenceInfo.Add("throttle", throttleInfo);
204
205 sceneInfo.Add(av.Name, presenceInfo);
206 }
207 regionInfo.Add(scene.RegionInfo.RegionName, sceneInfo);
208 }
209 return regionInfo.ToString();
210 }
211
132 public Dictionary<string, int> DecodeClientThrottles(byte[] throttle) 212 public Dictionary<string, int> DecodeClientThrottles(byte[] throttle)
133 { 213 {
134 Dictionary<string, int> returndict = new Dictionary<string, int>(); 214 Dictionary<string, int> returndict = new Dictionary<string, int>();
@@ -203,7 +283,7 @@ namespace OpenSim.Region.UserStatistics
203 returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; 283 returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++;
204 returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; 284 returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++;
205 returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; 285 returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++;
206 returndic.Add("Asset", rep.Substring((7 * pos), 8)); 286 returndic.Add("Asset", rep.Substring((7 * pos), 8));
207 /* 287 /*
208 * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", 288 * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
209 SendQueue.Count(), 289 SendQueue.Count(),
diff --git a/OpenSim/Region/UserStatistics/Clients_report.cs b/OpenSim/Region/UserStatistics/Clients_report.cs
index b2bb33b..4a6f7be 100644
--- a/OpenSim/Region/UserStatistics/Clients_report.cs
+++ b/OpenSim/Region/UserStatistics/Clients_report.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.Text; 31using System.Text;
32using Mono.Data.SqliteClient; 32using Mono.Data.SqliteClient;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35 36
36namespace OpenSim.Region.UserStatistics 37namespace OpenSim.Region.UserStatistics
@@ -44,6 +45,32 @@ namespace OpenSim.Region.UserStatistics
44 get { return "Client"; } 45 get { return "Client"; }
45 } 46 }
46 47
48 /// <summary>
49 /// Return summar information in the form:
50 /// <pre>
51 /// {"totalUsers": "34",
52 /// "totalSessions": "233",
53 /// ...
54 /// }
55 /// </pre>
56 /// </summary>
57 /// <param name="pModelResult"></param>
58 /// <returns></returns>
59 public string RenderJson(Hashtable pModelResult) {
60 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
61
62 OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap();
63 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
64 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
65 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
66 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
67 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
68 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
69 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
70 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
71 return summaryInfo.ToString();
72 }
73
47 public Hashtable ProcessModel(Hashtable pParams) 74 public Hashtable ProcessModel(Hashtable pParams)
48 { 75 {
49 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; 76 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];
diff --git a/OpenSim/Region/UserStatistics/Default_Report.cs b/OpenSim/Region/UserStatistics/Default_Report.cs
index cdc615c..fabe3d4 100644
--- a/OpenSim/Region/UserStatistics/Default_Report.cs
+++ b/OpenSim/Region/UserStatistics/Default_Report.cs
@@ -32,6 +32,7 @@ using System.Reflection;
32using System.Text; 32using System.Text;
33using Mono.Data.SqliteClient; 33using Mono.Data.SqliteClient;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Framework.Monitoring; 37using OpenSim.Framework.Monitoring;
37 38
@@ -230,6 +231,31 @@ TD.align_top { vertical-align: top; }
230 return returnstruct; 231 return returnstruct;
231 } 232 }
232 233
234 /// <summary>
235 /// Return summar information in the form:
236 /// <pre>
237 /// {"totalUsers": "34",
238 /// "totalSessions": "233",
239 /// ...
240 /// }
241 /// </pre>
242 /// </summary>
243 /// <param name="pModelResult"></param>
244 /// <returns></returns>
245 public string RenderJson(Hashtable pModelResult) {
246 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
247
248 OSDMap summaryInfo = new OSDMap();
249 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
250 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
251 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
252 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
253 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
254 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
255 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
256 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
257 return summaryInfo.ToString();
258 }
233 } 259 }
234 260
235 public struct stats_default_page_values 261 public struct stats_default_page_values
@@ -247,4 +273,5 @@ TD.align_top { vertical-align: top; }
247 public Dictionary<UUID, USimStatsData> sim_stat_data; 273 public Dictionary<UUID, USimStatsData> sim_stat_data;
248 public Dictionary<string, IStatsController> stats_reports; 274 public Dictionary<string, IStatsController> stats_reports;
249 } 275 }
276
250} 277}
diff --git a/OpenSim/Region/UserStatistics/IStatsReport.cs b/OpenSim/Region/UserStatistics/IStatsReport.cs
index e0ecce4..80c4487 100644
--- a/OpenSim/Region/UserStatistics/IStatsReport.cs
+++ b/OpenSim/Region/UserStatistics/IStatsReport.cs
@@ -34,5 +34,6 @@ namespace OpenSim.Region.UserStatistics
34 string ReportName { get; } 34 string ReportName { get; }
35 Hashtable ProcessModel(Hashtable pParams); 35 Hashtable ProcessModel(Hashtable pParams);
36 string RenderView(Hashtable pModelResult); 36 string RenderView(Hashtable pModelResult);
37 string RenderJson(Hashtable pModelResult);
37 } 38 }
38} 39}
diff --git a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs
index 74de46b..4d45b80 100644
--- a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs
+++ b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs
@@ -33,6 +33,7 @@ using System.Text;
33using System.Text.RegularExpressions; 33using System.Text.RegularExpressions;
34using Mono.Data.SqliteClient; 34using Mono.Data.SqliteClient;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring; 38using OpenSim.Framework.Monitoring;
38 39
@@ -125,6 +126,34 @@ namespace OpenSim.Region.UserStatistics
125 return output.ToString(); 126 return output.ToString();
126 } 127 }
127 128
129 /// <summary>
130 /// Return the last log lines. Output in the format:
131 /// <pre>
132 /// {"logLines": [
133 /// "line1",
134 /// "line2",
135 /// ...
136 /// ]
137 /// }
138 /// </pre>
139 /// </summary>
140 /// <param name="pModelResult"></param>
141 /// <returns></returns>
142 public string RenderJson(Hashtable pModelResult)
143 {
144 OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap();
145
146 OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray();
147 string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
148 string[] result = Regex.Split(tmp, "\n");
149 for (int i = 0; i < result.Length; i++)
150 {
151 logLines.Add(new OSDString(result[i]));
152 }
153 logInfo.Add("logLines", logLines);
154 return logInfo.ToString();
155 }
156
128 #endregion 157 #endregion
129 } 158 }
130} 159}
diff --git a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs
index 100cf99..1fff12a 100644
--- a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Region/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/UserStatistics/Prototype_distributor.cs
index 53ae557..6f8b2aa 100644
--- a/OpenSim/Region/UserStatistics/Prototype_distributor.cs
+++ b/OpenSim/Region/UserStatistics/Prototype_distributor.cs
@@ -36,7 +36,18 @@ namespace OpenSim.Region.UserStatistics
36{ 36{
37 public class Prototype_distributor : IStatsController 37 public class Prototype_distributor : IStatsController
38 { 38 {
39 private string prototypejs=string.Empty; 39 private string jsFileName = "prototype.js";
40 private string prototypejs = string.Empty;
41
42 public Prototype_distributor()
43 {
44 jsFileName = "prototype.js";
45 }
46
47 public Prototype_distributor(string jsName)
48 {
49 jsFileName = jsName;
50 }
40 51
41 public string ReportName 52 public string ReportName
42 { 53 {
@@ -45,20 +56,24 @@ namespace OpenSim.Region.UserStatistics
45 public Hashtable ProcessModel(Hashtable pParams) 56 public Hashtable ProcessModel(Hashtable pParams)
46 { 57 {
47 Hashtable pResult = new Hashtable(); 58 Hashtable pResult = new Hashtable();
48 if (prototypejs.Length == 0) 59 pResult["js"] = jsFileName;
60 return pResult;
61 }
62
63 public string RenderView(Hashtable pModelResult)
64 {
65 string fileName = (string)pModelResult["js"];
66 using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open)))
49 { 67 {
50 StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open));
51 prototypejs = fs.ReadToEnd(); 68 prototypejs = fs.ReadToEnd();
52 fs.Close(); 69 fs.Close();
53 fs.Dispose();
54 } 70 }
55 pResult["js"] = prototypejs; 71 return prototypejs;
56 return pResult;
57 } 72 }
58 73
59 public string RenderView(Hashtable pModelResult) 74 public string RenderJson(Hashtable pModelResult)
60 { 75 {
61 return pModelResult["js"].ToString(); 76 return "{}";
62 } 77 }
63 78
64 } 79 }
diff --git a/OpenSim/Region/UserStatistics/Sessions_Report.cs b/OpenSim/Region/UserStatistics/Sessions_Report.cs
index 1a2d460..0e94912 100644
--- a/OpenSim/Region/UserStatistics/Sessions_Report.cs
+++ b/OpenSim/Region/UserStatistics/Sessions_Report.cs
@@ -278,6 +278,11 @@ TD.align_top { vertical-align: top; }
278 public DateTime start_time; 278 public DateTime start_time;
279 } 279 }
280 280
281 public string RenderJson(Hashtable pModelResult)
282 {
283 return "{}";
284 }
281 #endregion 285 #endregion
282 } 286 }
287
283} 288}
diff --git a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs
index 28051fb..ad848a1 100644
--- a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs
+++ b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs
@@ -32,6 +32,7 @@ using System.Reflection;
32using System.Text; 32using System.Text;
33using Mono.Data.SqliteClient; 33using Mono.Data.SqliteClient;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Framework.Monitoring; 37using OpenSim.Framework.Monitoring;
37 38
@@ -218,6 +219,64 @@ namespace OpenSim.Region.UserStatistics
218 return output.ToString(); 219 return output.ToString();
219 } 220 }
220 221
222 /// <summary>
223 /// Return stat information for all regions in the sim. Returns data of the form:
224 /// <pre>
225 /// {"REGIONNAME": {
226 /// "region": "REGIONNAME",
227 /// "timeDilation": "101",
228 /// ... // the rest of the stat info
229 /// },
230 /// ... // entries for each region
231 /// }
232 /// </pre>
233 /// </summary>
234 /// <param name="pModelResult"></param>
235 /// <returns></returns>
236 public string RenderJson(Hashtable pModelResult)
237 {
238 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
239 Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
240
241 OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap();
242 foreach (USimStatsData sdata in sdatadic.Values)
243 {
244 OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap();
245 string regionName = "unknown";
246 foreach (Scene sn in all_scenes)
247 {
248 if (sn.RegionInfo.RegionID == sdata.RegionId)
249 {
250 regionName = sn.RegionInfo.RegionName;
251 break;
252 }
253 }
254 statsInfo.Add("region", new OSDString(regionName));
255 statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString()));
256 statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString()));
257 statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString()));
258 statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString()));
259 statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString()));
260 statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString()));
261 statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString()));
262 statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString()));
263 statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString()));
264 statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString()));
265 statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString()));
266 statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString()));
267 statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString()));
268 statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString()));
269 statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString()));
270 statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString()));
271 statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString()));
272 statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString()));
273 statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString()));
274
275 allStatsInfo.Add(regionName, statsInfo);
276 }
277 return allStatsInfo.ToString();
278 }
279
221 #endregion 280 #endregion
222 } 281 }
223} 282}
diff --git a/OpenSim/Region/UserStatistics/Updater_distributor.cs b/OpenSim/Region/UserStatistics/Updater_distributor.cs
index 9593cc9..601e06b 100644
--- a/OpenSim/Region/UserStatistics/Updater_distributor.cs
+++ b/OpenSim/Region/UserStatistics/Updater_distributor.cs
@@ -62,5 +62,9 @@ namespace OpenSim.Region.UserStatistics
62 return pModelResult["js"].ToString(); 62 return pModelResult["js"].ToString();
63 } 63 }
64 64
65 public string RenderJson(Hashtable pModelResult) {
66 return "{}";
67 }
68
65 } 69 }
66} \ No newline at end of file 70} \ No newline at end of file
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
index b08233c..b98b762 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
@@ -123,6 +121,10 @@ namespace OpenSim.Region.UserStatistics
123 reports.Add("clients.report", clientReport); 121 reports.Add("clients.report", clientReport);
124 reports.Add("sessions.report", sessionsReport); 122 reports.Add("sessions.report", sessionsReport);
125 123
124 reports.Add("sim.css", new Prototype_distributor("sim.css"));
125 reports.Add("sim.html", new Prototype_distributor("sim.html"));
126 reports.Add("jquery.js", new Prototype_distributor("jquery.js"));
127
126 //// 128 ////
127 // Add Your own Reports here (Do Not Modify Lines here Devs!) 129 // Add Your own Reports here (Do Not Modify Lines here Devs!)
128 //// 130 ////
@@ -143,10 +145,14 @@ namespace OpenSim.Region.UserStatistics
143 lock (m_scenes) 145 lock (m_scenes)
144 { 146 {
145 m_scenes.Add(scene); 147 m_scenes.Add(scene);
146 if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID)) 148 updateLogMod = m_scenes.Count * 2;
147 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
148 149
149 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); 150 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
151
152 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
153 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
154 scene.EventManager.OnClientClosed += OnClientClosed;
155 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
150 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; 156 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
151 } 157 }
152 } 158 }
@@ -157,6 +163,15 @@ namespace OpenSim.Region.UserStatistics
157 163
158 public void RemoveRegion(Scene scene) 164 public void RemoveRegion(Scene scene)
159 { 165 {
166 if (!enabled)
167 return;
168
169 lock (m_scenes)
170 {
171 m_scenes.Remove(scene);
172 updateLogMod = m_scenes.Count * 2;
173 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
174 }
160 } 175 }
161 176
162 public virtual void Close() 177 public virtual void Close()
@@ -187,9 +202,7 @@ namespace OpenSim.Region.UserStatistics
187 private void ReceiveClassicSimStatsPacket(SimStats stats) 202 private void ReceiveClassicSimStatsPacket(SimStats stats)
188 { 203 {
189 if (!enabled) 204 if (!enabled)
190 {
191 return; 205 return;
192 }
193 206
194 try 207 try
195 { 208 {
@@ -198,17 +211,25 @@ namespace OpenSim.Region.UserStatistics
198 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) 211 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
199 return; 212 return;
200 213
201 if ((updateLogCounter++ % updateLogMod) == 0) 214 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
215 // confused if a scene is removed.
216 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
217 lock (m_scenes)
202 { 218 {
203 m_loglines = readLogLines(10); 219 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
204 if (updateLogCounter > 10000) updateLogCounter = 1; 220 {
205 } 221 m_loglines = readLogLines(10);
222
223 if (updateLogCounter > 10000)
224 updateLogCounter = 1;
225 }
206 226
207 USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; 227 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
208 228
209 if ((++ss.StatsCounter % updateStatsMod) == 0) 229 if ((++ss.StatsCounter % updateStatsMod) == 0)
210 { 230 {
211 ss.ConsumeSimStats(stats); 231 ss.ConsumeSimStats(stats);
232 }
212 } 233 }
213 } 234 }
214 catch (KeyNotFoundException) 235 catch (KeyNotFoundException)
@@ -238,9 +259,12 @@ namespace OpenSim.Region.UserStatistics
238 string regpath = request["uri"].ToString(); 259 string regpath = request["uri"].ToString();
239 int response_code = 404; 260 int response_code = 404;
240 string contenttype = "text/html"; 261 string contenttype = "text/html";
262 bool jsonFormatOutput = false;
241 263
242 string strOut = string.Empty; 264 string strOut = string.Empty;
243 265
266 // The request patch should be "/SStats/reportName" where 'reportName'
267 // is one of the names added to the 'reports' hashmap.
244 regpath = regpath.Remove(0, 8); 268 regpath = regpath.Remove(0, 8);
245 if (regpath.Length == 0) regpath = "default.report"; 269 if (regpath.Length == 0) regpath = "default.report";
246 if (reports.ContainsKey(regpath)) 270 if (reports.ContainsKey(regpath))
@@ -248,6 +272,9 @@ namespace OpenSim.Region.UserStatistics
248 IStatsController rep = reports[regpath]; 272 IStatsController rep = reports[regpath];
249 Hashtable repParams = new Hashtable(); 273 Hashtable repParams = new Hashtable();
250 274
275 if (request.ContainsKey("json"))
276 jsonFormatOutput = true;
277
251 if (request.ContainsKey("requestvars")) 278 if (request.ContainsKey("requestvars"))
252 repParams["RequestVars"] = request["requestvars"]; 279 repParams["RequestVars"] = request["requestvars"];
253 else 280 else
@@ -267,13 +294,26 @@ namespace OpenSim.Region.UserStatistics
267 294
268 concurrencyCounter++; 295 concurrencyCounter++;
269 296
270 strOut = rep.RenderView(rep.ProcessModel(repParams)); 297 if (jsonFormatOutput)
298 {
299 strOut = rep.RenderJson(rep.ProcessModel(repParams));
300 contenttype = "text/json";
301 }
302 else
303 {
304 strOut = rep.RenderView(rep.ProcessModel(repParams));
305 }
271 306
272 if (regpath.EndsWith("js")) 307 if (regpath.EndsWith("js"))
273 { 308 {
274 contenttype = "text/javascript"; 309 contenttype = "text/javascript";
275 } 310 }
276 311
312 if (regpath.EndsWith("css"))
313 {
314 contenttype = "text/css";
315 }
316
277 concurrencyCounter--; 317 concurrencyCounter--;
278 318
279 response_code = 200; 319 response_code = 200;
@@ -380,7 +420,7 @@ namespace OpenSim.Region.UserStatistics
380 Encoding encoding = Encoding.ASCII; 420 Encoding encoding = Encoding.ASCII;
381 int sizeOfChar = encoding.GetByteCount("\n"); 421 int sizeOfChar = encoding.GetByteCount("\n");
382 byte[] buffer = encoding.GetBytes("\n"); 422 byte[] buffer = encoding.GetBytes("\n");
383 string logfile = Util.logDir() + "/" + "OpenSim.log"; 423 string logfile = Util.logFile();
384 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 424 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
385 Int64 tokenCount = 0; 425 Int64 tokenCount = 0;
386 Int64 endPosition = fs.Length / sizeOfChar; 426 Int64 endPosition = fs.Length / sizeOfChar;
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/Properties/AssemblyInfo.cs b/OpenSim/Server/Base/Properties/AssemblyInfo.cs
index 4bbe358..b4732b8 100644
--- a/OpenSim/Server/Base/Properties/AssemblyInfo.cs
+++ b/OpenSim/Server/Base/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs
index 42c82cf..210a314 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 UTILS]: 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 UTILS]: 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 UTILS]: 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 UTILS]: {0} Disabled.", connector.ConfigName);
170 }
171 }
172
173 private void UnloadPlugin(IRobustConnector connector)
174 {
175 m_log.InfoFormat("[SERVER UTILS]: 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("[SERVER UTILS]: 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 }
@@ -133,14 +298,14 @@ namespace OpenSim.Server.Base
133 } 298 }
134 catch (ReflectionTypeLoadException rtle) 299 catch (ReflectionTypeLoadException rtle)
135 { 300 {
136 m_log.Error(string.Format("Error loading plugin from {0}:\n{1}", dllName, 301 m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName,
137 String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))), 302 String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))),
138 rtle); 303 rtle);
139 return null; 304 return null;
140 } 305 }
141 catch (Exception e) 306 catch (Exception e)
142 { 307 {
143 m_log.Error(string.Format("Error loading plugin from {0}", dllName), e); 308 m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e);
144 return null; 309 return null;
145 } 310 }
146 } 311 }
@@ -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("[SERVER UTILS]: {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("[SERVER UTILS]: 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..7c8e6b7 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
@@ -178,6 +186,7 @@ namespace OpenSim.Server.Base
178 XmlConfigurator.Configure(); 186 XmlConfigurator.Configure();
179 } 187 }
180 188
189 LogEnvironmentInformation();
181 RegisterCommonAppenders(startupConfig); 190 RegisterCommonAppenders(startupConfig);
182 191
183 if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty) 192 if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty)
@@ -242,4 +251,4 @@ namespace OpenSim.Server.Base
242 { 251 {
243 } 252 }
244 } 253 }
245} \ No newline at end of file 254}
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/Handlers/Grid/GridInfoHandlers.cs b/OpenSim/Server/Handlers/Grid/GridInfoHandlers.cs
index 965a54e..346af32 100644
--- a/OpenSim/Server/Handlers/Grid/GridInfoHandlers.cs
+++ b/OpenSim/Server/Handlers/Grid/GridInfoHandlers.cs
@@ -170,14 +170,6 @@ namespace OpenSim.Server.Handlers.Grid
170 public string JsonGetGridInfoMethod(string request, string path, string param, 170 public string JsonGetGridInfoMethod(string request, string path, string param,
171 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 171 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
172 { 172 {
173 string HomeURI = String.Empty;
174 IConfig cfg = m_Config.Configs["LoginService"];
175
176 if (null != cfg)
177 {
178 HomeURI = cfg.GetString("SRV_HomeURI", HomeURI);
179 }
180
181 OSDMap map = new OSDMap(); 173 OSDMap map = new OSDMap();
182 174
183 foreach (string k in _info.Keys) 175 foreach (string k in _info.Keys)
@@ -185,9 +177,20 @@ namespace OpenSim.Server.Handlers.Grid
185 map[k] = OSD.FromString(_info[k].ToString()); 177 map[k] = OSD.FromString(_info[k].ToString());
186 } 178 }
187 179
180 string HomeURI = Util.GetConfigVarFromSections<string>(m_Config, "HomeURI",
181 new string[] { "Startup", "Hypergrid" }, String.Empty);
182
188 if (!String.IsNullOrEmpty(HomeURI)) 183 if (!String.IsNullOrEmpty(HomeURI))
184 map["home"] = OSD.FromString(HomeURI);
185 else // Legacy. Remove soon!
189 { 186 {
190 map["home"] = OSD.FromString(HomeURI); 187 IConfig cfg = m_Config.Configs["LoginService"];
188
189 if (null != cfg)
190 HomeURI = cfg.GetString("SRV_HomeURI", HomeURI);
191
192 if (!String.IsNullOrEmpty(HomeURI))
193 map["home"] = OSD.FromString(HomeURI);
191 } 194 }
192 195
193 return OSDParser.SerializeJsonString(map).ToString(); 196 return OSDParser.SerializeJsonString(map).ToString();
diff --git a/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs
index 53e9737..3295ffd 100644
--- a/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Server/Properties/AssemblyInfo.cs b/OpenSim/Server/Properties/AssemblyInfo.cs
index ebc10fb..ee45e10 100644
--- a/OpenSim/Server/Properties/AssemblyInfo.cs
+++ b/OpenSim/Server/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs
index 45c13fb..65e9287 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)
@@ -138,9 +145,12 @@ namespace OpenSim.Server
138 } 145 }
139 else 146 else
140 { 147 {
141 m_log.InfoFormat("[SERVER]: Failed to load {0}", conn); 148 m_log.ErrorFormat("[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/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs
index f1bffa4..90c30c8 100644
--- a/OpenSim/Services/AssetService/AssetService.cs
+++ b/OpenSim/Services/AssetService/AssetService.cs
@@ -123,46 +123,32 @@ namespace OpenSim.Services.AssetService
123 public virtual AssetMetadata GetMetadata(string id) 123 public virtual AssetMetadata GetMetadata(string id)
124 { 124 {
125// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id); 125// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id);
126
127 UUID assetID;
128 126
129 if (!UUID.TryParse(id, out assetID)) 127 AssetBase asset = Get(id);
130 return null;
131 128
132 AssetBase asset = m_Database.GetAsset(assetID);
133 if (asset != null) 129 if (asset != null)
134 return asset.Metadata; 130 return asset.Metadata;
135 131 else
136 return null; 132 return null;
137 } 133 }
138 134
139 public virtual byte[] GetData(string id) 135 public virtual byte[] GetData(string id)
140 { 136 {
141// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id); 137// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id);
142
143 UUID assetID;
144 138
145 if (!UUID.TryParse(id, out assetID)) 139 AssetBase asset = Get(id);
146 return null;
147 140
148 AssetBase asset = m_Database.GetAsset(assetID); 141 if (asset != null)
149 return asset.Data; 142 return asset.Data;
143 else
144 return null;
150 } 145 }
151 146
152 public virtual bool Get(string id, Object sender, AssetRetrieved handler) 147 public virtual bool Get(string id, Object sender, AssetRetrieved handler)
153 { 148 {
154 //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); 149 //m_log.DebugFormat("[AssetService]: Get asset async {0}", id);
155
156 UUID assetID;
157 150
158 if (!UUID.TryParse(id, out assetID)) 151 handler(id, sender, Get(id));
159 return false;
160
161 AssetBase asset = m_Database.GetAsset(assetID);
162
163 //m_log.DebugFormat("[AssetService]: Got asset {0}", asset);
164
165 handler(id, sender, asset);
166 152
167 return true; 153 return true;
168 } 154 }
diff --git a/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs b/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs
index 1509400..50ee033 100644
--- a/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs
index a1d10ed..8a2ca7c 100644
--- a/OpenSim/Services/AssetService/XAssetService.cs
+++ b/OpenSim/Services/AssetService/XAssetService.cs
@@ -39,8 +39,7 @@ using OpenMetaverse;
39namespace OpenSim.Services.AssetService 39namespace OpenSim.Services.AssetService
40{ 40{
41 /// <summary> 41 /// <summary>
42 /// This will be developed into a de-duplicating asset service. 42 /// A de-duplicating asset service.
43 /// XXX: Currently it's a just a copy of the existing AssetService. so please don't attempt to use it.
44 /// </summary> 43 /// </summary>
45 public class XAssetService : XAssetServiceBase, IAssetService 44 public class XAssetService : XAssetServiceBase, IAssetService
46 { 45 {
@@ -48,7 +47,9 @@ namespace OpenSim.Services.AssetService
48 47
49 protected static XAssetService m_RootInstance; 48 protected static XAssetService m_RootInstance;
50 49
51 public XAssetService(IConfigSource config) : base(config) 50 public XAssetService(IConfigSource config) : this(config, "AssetService") {}
51
52 public XAssetService(IConfigSource config, string configName) : base(config, configName)
52 { 53 {
53 if (m_RootInstance == null) 54 if (m_RootInstance == null)
54 { 55 {
@@ -56,22 +57,21 @@ namespace OpenSim.Services.AssetService
56 57
57 if (m_AssetLoader != null) 58 if (m_AssetLoader != null)
58 { 59 {
59 IConfig assetConfig = config.Configs["AssetService"]; 60 IConfig assetConfig = config.Configs[configName];
60 if (assetConfig == null) 61 if (assetConfig == null)
61 throw new Exception("No AssetService configuration"); 62 throw new Exception("No AssetService configuration");
62 63
63 string loaderArgs = assetConfig.GetString("AssetLoaderArgs", 64 string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty);
64 String.Empty);
65 65
66 bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); 66 bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
67 67
68 if (assetLoaderEnabled) 68 if (assetLoaderEnabled && !HasChainedAssetService)
69 { 69 {
70 m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs); 70 m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
71 71
72 m_AssetLoader.ForEachDefaultXmlAsset( 72 m_AssetLoader.ForEachDefaultXmlAsset(
73 loaderArgs, 73 loaderArgs,
74 delegate(AssetBase a) 74 a =>
75 { 75 {
76 AssetBase existingAsset = Get(a.ID); 76 AssetBase existingAsset = Get(a.ID);
77// AssetMetadata existingMetadata = GetMetadata(a.ID); 77// AssetMetadata existingMetadata = GetMetadata(a.ID);
@@ -103,7 +103,23 @@ namespace OpenSim.Services.AssetService
103 103
104 try 104 try
105 { 105 {
106 return m_Database.GetAsset(assetID); 106 AssetBase asset = m_Database.GetAsset(assetID);
107
108 if (asset != null)
109 {
110 return asset;
111 }
112 else if (HasChainedAssetService)
113 {
114 asset = m_ChainedAssetService.Get(id);
115
116 if (asset != null)
117 MigrateFromChainedService(asset);
118
119 return asset;
120 }
121
122 return null;
107 } 123 }
108 catch (Exception e) 124 catch (Exception e)
109 { 125 {
@@ -120,30 +136,25 @@ namespace OpenSim.Services.AssetService
120 public virtual AssetMetadata GetMetadata(string id) 136 public virtual AssetMetadata GetMetadata(string id)
121 { 137 {
122// m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id); 138// m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id);
123
124 UUID assetID;
125 139
126 if (!UUID.TryParse(id, out assetID)) 140 AssetBase asset = Get(id);
127 return null;
128 141
129 AssetBase asset = m_Database.GetAsset(assetID);
130 if (asset != null) 142 if (asset != null)
131 return asset.Metadata; 143 return asset.Metadata;
132 144 else
133 return null; 145 return null;
134 } 146 }
135 147
136 public virtual byte[] GetData(string id) 148 public virtual byte[] GetData(string id)
137 { 149 {
138// m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id); 150// m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id);
139 151
140 UUID assetID; 152 AssetBase asset = Get(id);
141 153
142 if (!UUID.TryParse(id, out assetID)) 154 if (asset != null)
155 return asset.Data;
156 else
143 return null; 157 return null;
144
145 AssetBase asset = m_Database.GetAsset(assetID);
146 return asset.Data;
147 } 158 }
148 159
149 public virtual bool Get(string id, Object sender, AssetRetrieved handler) 160 public virtual bool Get(string id, Object sender, AssetRetrieved handler)
@@ -155,7 +166,7 @@ namespace OpenSim.Services.AssetService
155 if (!UUID.TryParse(id, out assetID)) 166 if (!UUID.TryParse(id, out assetID))
156 return false; 167 return false;
157 168
158 AssetBase asset = m_Database.GetAsset(assetID); 169 AssetBase asset = Get(id);
159 170
160 //m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset); 171 //m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset);
161 172
@@ -194,7 +205,15 @@ namespace OpenSim.Services.AssetService
194 if (!UUID.TryParse(id, out assetID)) 205 if (!UUID.TryParse(id, out assetID))
195 return false; 206 return false;
196 207
208 // Don't bother deleting from a chained asset service. This isn't a big deal since deleting happens
209 // very rarely.
210
197 return m_Database.Delete(id); 211 return m_Database.Delete(id);
198 } 212 }
213
214 private void MigrateFromChainedService(AssetBase asset)
215 {
216 Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); });
217 }
199 } 218 }
200} \ No newline at end of file 219} \ No newline at end of file
diff --git a/OpenSim/Services/AssetService/XAssetServiceBase.cs b/OpenSim/Services/AssetService/XAssetServiceBase.cs
index 0c5c2c3..c118c9d 100644
--- a/OpenSim/Services/AssetService/XAssetServiceBase.cs
+++ b/OpenSim/Services/AssetService/XAssetServiceBase.cs
@@ -27,9 +27,11 @@
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Reflection;
30using log4net;
30using Nini.Config; 31using Nini.Config;
31using OpenSim.Framework; 32using OpenSim.Framework;
32using OpenSim.Data; 33using OpenSim.Data;
34using OpenSim.Server.Base;
33using OpenSim.Services.Interfaces; 35using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base; 36using OpenSim.Services.Base;
35 37
@@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService
37{ 39{
38 public class XAssetServiceBase : ServiceBase 40 public class XAssetServiceBase : ServiceBase
39 { 41 {
40 protected IXAssetDataPlugin m_Database = null; 42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41 protected IAssetLoader m_AssetLoader = null;
42 43
43 public XAssetServiceBase(IConfigSource config) : base(config) 44 protected IXAssetDataPlugin m_Database;
45 protected IAssetLoader m_AssetLoader;
46 protected IAssetService m_ChainedAssetService;
47
48 protected bool HasChainedAssetService { get { return m_ChainedAssetService != null; } }
49
50 public XAssetServiceBase(IConfigSource config, string configName) : base(config)
44 { 51 {
45 string dllName = String.Empty; 52 string dllName = String.Empty;
46 string connString = String.Empty; 53 string connString = String.Empty;
@@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService
48 // 55 //
49 // Try reading the [AssetService] section first, if it exists 56 // Try reading the [AssetService] section first, if it exists
50 // 57 //
51 IConfig assetConfig = config.Configs["AssetService"]; 58 IConfig assetConfig = config.Configs[configName];
52 if (assetConfig != null) 59 if (assetConfig != null)
53 { 60 {
54 dllName = assetConfig.GetString("StorageProvider", dllName); 61 dllName = assetConfig.GetString("StorageProvider", dllName);
@@ -77,17 +84,35 @@ namespace OpenSim.Services.AssetService
77 if (m_Database == null) 84 if (m_Database == null)
78 throw new Exception("Could not find a storage interface in the given module"); 85 throw new Exception("Could not find a storage interface in the given module");
79 86
80 m_Database.Initialise(connString); 87 string chainedAssetServiceDesignator = assetConfig.GetString("ChainedServiceModule", null);
88
89 if (chainedAssetServiceDesignator != null)
90 {
91 m_log.InfoFormat(
92 "[XASSET SERVICE BASE]: Loading chained asset service from {0}", chainedAssetServiceDesignator);
81 93
82 string loaderName = assetConfig.GetString("DefaultAssetLoader", 94 Object[] args = new Object[] { config, configName };
83 String.Empty); 95 m_ChainedAssetService = ServerUtils.LoadPlugin<IAssetService>(chainedAssetServiceDesignator, args);
84 96
85 if (loaderName != String.Empty) 97 if (!HasChainedAssetService)
98 throw new Exception(
99 String.Format("Failed to load ChainedAssetService from {0}", chainedAssetServiceDesignator));
100 }
101
102 m_Database.Initialise(connString);
103
104 if (HasChainedAssetService)
86 { 105 {
87 m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName); 106 string loaderName = assetConfig.GetString("DefaultAssetLoader",
107 String.Empty);
108
109 if (loaderName != String.Empty)
110 {
111 m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
88 112
89 if (m_AssetLoader == null) 113 if (m_AssetLoader == null)
90 throw new Exception("Asset loader could not be loaded"); 114 throw new Exception("Asset loader could not be loaded");
115 }
91 } 116 }
92 } 117 }
93 } 118 }
diff --git a/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs b/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs
index 0eb2ba7..435852da 100644
--- a/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs b/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs
index 6d6b11e..8db1671 100644
--- a/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs b/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs
index 0944149..138d4cd 100644
--- a/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/Base/Properties/AssemblyInfo.cs b/OpenSim/Services/Base/Properties/AssemblyInfo.cs
index 306b699..84a40f0 100644
--- a/OpenSim/Services/Base/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/Base/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs
index 5c50936..5004d99 100644
--- a/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs
+++ b/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs
@@ -73,7 +73,6 @@ namespace OpenSim.Services.Connectors
73 } 73 }
74 } 74 }
75 75
76
77 public virtual string Helo() 76 public virtual string Helo()
78 { 77 {
79 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI); 78 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI);
@@ -82,10 +81,12 @@ namespace OpenSim.Services.Connectors
82 81
83 try 82 try
84 { 83 {
85 WebResponse response = req.GetResponse(); 84 using (WebResponse response = req.GetResponse())
86 if (response.Headers.Get("X-Handlers-Provided") == null) // just in case this ever returns a null 85 {
87 return string.Empty; 86 if (response.Headers.Get("X-Handlers-Provided") == null) // just in case this ever returns a null
88 return response.Headers.Get("X-Handlers-Provided"); 87 return string.Empty;
88 return response.Headers.Get("X-Handlers-Provided");
89 }
89 } 90 }
90 catch (Exception e) 91 catch (Exception e)
91 { 92 {
@@ -95,6 +96,5 @@ namespace OpenSim.Services.Connectors
95 // fail 96 // fail
96 return string.Empty; 97 return string.Empty;
97 } 98 }
98
99 } 99 }
100} 100} \ No newline at end of file
diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
index c542c29..d7e38f1 100644
--- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
@@ -169,41 +169,45 @@ namespace OpenSim.Services.Connectors.Hypergrid
169 // Let's wait for the response 169 // Let's wait for the response
170 //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall"); 170 //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall");
171 171
172 WebResponse webResponse = null;
173 StreamReader sr = null;
174 try 172 try
175 { 173 {
176 webResponse = AgentCreateRequest.GetResponse(); 174 using (WebResponse webResponse = AgentCreateRequest.GetResponse())
177 if (webResponse == null)
178 { 175 {
179 m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post"); 176 if (webResponse == null)
180 }
181 else
182 {
183
184 sr = new StreamReader(webResponse.GetResponseStream());
185 string response = sr.ReadToEnd().Trim();
186 m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response);
187
188 if (!String.IsNullOrEmpty(response))
189 { 177 {
190 try 178 m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post");
191 { 179 }
192 // we assume we got an OSDMap back 180 else
193 OSDMap r = Util.GetOSDMap(response); 181 {
194 bool success = r["success"].AsBoolean(); 182 using (Stream s = webResponse.GetResponseStream())
195 reason = r["reason"].AsString();
196 return success;
197 }
198 catch (NullReferenceException e)
199 { 183 {
200 m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message); 184 using (StreamReader sr = new StreamReader(s))
201 185 {
202 // check for old style response 186 string response = sr.ReadToEnd().Trim();
203 if (response.ToLower().StartsWith("true")) 187 m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response);
204 return true; 188
205 189 if (!String.IsNullOrEmpty(response))
206 return false; 190 {
191 try
192 {
193 // we assume we got an OSDMap back
194 OSDMap r = Util.GetOSDMap(response);
195 bool success = r["success"].AsBoolean();
196 reason = r["reason"].AsString();
197 return success;
198 }
199 catch (NullReferenceException e)
200 {
201 m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message);
202
203 // check for old style response
204 if (response.ToLower().StartsWith("true"))
205 return true;
206
207 return false;
208 }
209 }
210 }
207 } 211 }
208 } 212 }
209 } 213 }
@@ -214,11 +218,6 @@ namespace OpenSim.Services.Connectors.Hypergrid
214 reason = "Destination did not reply"; 218 reason = "Destination did not reply";
215 return false; 219 return false;
216 } 220 }
217 finally
218 {
219 if (sr != null)
220 sr.Close();
221 }
222 221
223 return true; 222 return true;
224 223
diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs
index 7688e0f..b36fa23 100644
--- a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs
+++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs
@@ -168,22 +168,27 @@ namespace OpenSim.Services.Connectors
168 // Let's wait for the response 168 // Let's wait for the response
169 //m_log.Info("[REST COMMS]: Waiting for a reply after DoHelloNeighbourCall"); 169 //m_log.Info("[REST COMMS]: Waiting for a reply after DoHelloNeighbourCall");
170 170
171 StreamReader sr = null;
172 try 171 try
173 { 172 {
174 WebResponse webResponse = helloNeighbourRequest.GetResponse(); 173 using (WebResponse webResponse = helloNeighbourRequest.GetResponse())
175 if (webResponse == null)
176 { 174 {
177 m_log.DebugFormat( 175 if (webResponse == null)
178 "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}", 176 {
179 thisRegion.RegionName, region.RegionName); 177 m_log.DebugFormat(
178 "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}",
179 thisRegion.RegionName, region.RegionName);
180 }
181
182 using (Stream s = webResponse.GetResponseStream())
183 {
184 using (StreamReader sr = new StreamReader(s))
185 {
186 //reply = sr.ReadToEnd().Trim();
187 sr.ReadToEnd().Trim();
188 //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply);
189 }
190 }
180 } 191 }
181
182 sr = new StreamReader(webResponse.GetResponseStream());
183 //reply = sr.ReadToEnd().Trim();
184 sr.ReadToEnd().Trim();
185 //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply);
186
187 } 192 }
188 catch (Exception e) 193 catch (Exception e)
189 { 194 {
@@ -193,11 +198,6 @@ namespace OpenSim.Services.Connectors
193 198
194 return false; 199 return false;
195 } 200 }
196 finally
197 {
198 if (sr != null)
199 sr.Close();
200 }
201 201
202 return true; 202 return true;
203 } 203 }
diff --git a/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs b/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs
index bfb681b..8b18afb 100644
--- a/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
index 63a32e7..74b980c 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
@@ -339,36 +339,38 @@ namespace OpenSim.Services.Connectors.SimianGrid
339 // Simian does not require the asset ID to be in the URL because it's in the post data. 339 // Simian does not require the asset ID to be in the URL because it's in the post data.
340 // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs 340 // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs
341 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); 341 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString());
342
343 HttpWebResponse response = MultipartForm.Post(request, postParameters);
344 using (Stream responseStream = response.GetResponseStream())
345 {
346 string responseStr = null;
347 342
348 try 343 using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
344 {
345 using (Stream responseStream = response.GetResponseStream())
349 { 346 {
350 responseStr = responseStream.GetStreamString(); 347 string responseStr = null;
351 OSD responseOSD = OSDParser.Deserialize(responseStr); 348
352 if (responseOSD.Type == OSDType.Map) 349 try
353 { 350 {
354 OSDMap responseMap = (OSDMap)responseOSD; 351 responseStr = responseStream.GetStreamString();
355 if (responseMap["Success"].AsBoolean()) 352 OSD responseOSD = OSDParser.Deserialize(responseStr);
356 return asset.ID; 353 if (responseOSD.Type == OSDType.Map)
354 {
355 OSDMap responseMap = (OSDMap)responseOSD;
356 if (responseMap["Success"].AsBoolean())
357 return asset.ID;
358 else
359 errorMessage = "Upload failed: " + responseMap["Message"].AsString();
360 }
357 else 361 else
358 errorMessage = "Upload failed: " + responseMap["Message"].AsString(); 362 {
363 errorMessage = "Response format was invalid:\n" + responseStr;
364 }
359 } 365 }
360 else 366 catch (Exception ex)
361 { 367 {
362 errorMessage = "Response format was invalid:\n" + responseStr; 368 if (!String.IsNullOrEmpty(responseStr))
369 errorMessage = "Failed to parse the response:\n" + responseStr;
370 else
371 errorMessage = "Failed to retrieve the response: " + ex.Message;
363 } 372 }
364 } 373 }
365 catch (Exception ex)
366 {
367 if (!String.IsNullOrEmpty(responseStr))
368 errorMessage = "Failed to parse the response:\n" + responseStr;
369 else
370 errorMessage = "Failed to retrieve the response: " + ex.Message;
371 }
372 } 374 }
373 } 375 }
374 catch (WebException ex) 376 catch (WebException ex)
@@ -378,6 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
378 380
379 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", 381 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
380 asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); 382 asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
383
381 return null; 384 return null;
382 } 385 }
383 386
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
index a391275..36325ce 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
@@ -38,12 +38,14 @@ using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Services.Connectors.SimianGrid 43namespace OpenSim.Services.Connectors.SimianGrid
43{ 44{
44 /// <summary> 45 /// <summary>
45 /// Permissions bitflags 46 /// Permissions bitflags
46 /// </summary> 47 /// </summary>
48 /*
47 [Flags] 49 [Flags]
48 public enum PermissionMask : uint 50 public enum PermissionMask : uint
49 { 51 {
@@ -55,6 +57,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
55 Damage = 1 << 20, 57 Damage = 1 << 20,
56 All = 0x7FFFFFFF 58 All = 0x7FFFFFFF
57 } 59 }
60 */
58 61
59 /// <summary> 62 /// <summary>
60 /// Connects avatar inventories to the SimianGrid backend 63 /// Connects avatar inventories to the SimianGrid backend
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/Connectors/UserAccounts/UserAccountServicesConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs
index 5731e2f..6b2d710 100644
--- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs
+++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs
@@ -162,7 +162,7 @@ namespace OpenSim.Services.Connectors
162 162
163 if (replyData != null) 163 if (replyData != null)
164 { 164 {
165 if (replyData.ContainsKey("result") && replyData.ContainsKey("result").ToString() == "null") 165 if (replyData.ContainsKey("result") && replyData["result"].ToString() == "null")
166 { 166 {
167 return accounts; 167 return accounts;
168 } 168 }
diff --git a/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs b/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs
index 58c7283..b488b36 100644
--- a/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/Friends/Properties/AssemblyInfo.cs b/OpenSim/Services/Friends/Properties/AssemblyInfo.cs
index dddb091..b11d07d 100644
--- a/OpenSim/Services/Friends/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/Friends/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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..8335724 100644
--- a/OpenSim/Services/GridService/HypergridLinker.cs
+++ b/OpenSim/Services/GridService/HypergridLinker.cs
@@ -128,7 +128,10 @@ namespace OpenSim.Services.GridService
128 128
129 m_MapTileDirectory = gridConfig.GetString("MapTileDirectory", "maptiles"); 129 m_MapTileDirectory = gridConfig.GetString("MapTileDirectory", "maptiles");
130 130
131 m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", string.Empty); 131 m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
132 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
133 // Legacy. Remove soon!
134 m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper);
132 try 135 try
133 { 136 {
134 m_ThisGatekeeperURI = new Uri(m_ThisGatekeeper); 137 m_ThisGatekeeperURI = new Uri(m_ThisGatekeeper);
@@ -387,7 +390,7 @@ namespace OpenSim.Services.GridService
387 m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName); 390 m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName);
388 GridRegion regInfo = null; 391 GridRegion regInfo = null;
389 392
390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); 393 List<RegionData> regions = m_Database.Get(Util.EscapeForLike(mapName), m_ScopeID);
391 if (regions != null && regions.Count > 0) 394 if (regions != null && regions.Count > 0)
392 { 395 {
393 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); 396 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
diff --git a/OpenSim/Services/GridService/Properties/AssemblyInfo.cs b/OpenSim/Services/GridService/Properties/AssemblyInfo.cs
index 5c0c8f4..b1e5e12 100644
--- a/OpenSim/Services/GridService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/GridService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
index 7b84d55..97a0afc 100644
--- a/OpenSim/Services/HypergridService/GatekeeperService.cs
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -96,7 +96,9 @@ namespace OpenSim.Services.HypergridService
96 UUID.TryParse(scope, out m_ScopeID); 96 UUID.TryParse(scope, out m_ScopeID);
97 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!"); 97 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
98 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true); 98 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true);
99 m_ExternalName = serverConfig.GetString("ExternalName", string.Empty); 99 m_ExternalName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
100 new string[] { "Startup", "Hypergrid", "GatekeeperService" }, String.Empty);
101 m_ExternalName = serverConfig.GetString("ExternalName", m_ExternalName);
100 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/")) 102 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
101 m_ExternalName = m_ExternalName + "/"; 103 m_ExternalName = m_ExternalName + "/";
102 104
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/HypergridService/HGInventoryService.cs b/OpenSim/Services/HypergridService/HGInventoryService.cs
index 2e9bd40..326e68d 100644
--- a/OpenSim/Services/HypergridService/HGInventoryService.cs
+++ b/OpenSim/Services/HypergridService/HGInventoryService.cs
@@ -81,10 +81,8 @@ namespace OpenSim.Services.HypergridService
81 if (m_UserAccountService == null) 81 if (m_UserAccountService == null)
82 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); 82 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
83 83
84 // legacy configuration [obsolete] 84 m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
85 m_HomeURL = invConfig.GetString("ProfileServerURI", string.Empty); 85 new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty);
86 // Preferred
87 m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL);
88 86
89 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); 87 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
90 } 88 }
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
index 784f136..eecf757 100644
--- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -96,8 +96,8 @@ namespace OpenSim.Services.HypergridService
96 if (m_AvatarService == null) 96 if (m_AvatarService == null)
97 throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll)); 97 throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll));
98 98
99 // Preferred 99 m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
100 m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); 100 new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty);
101 101
102// m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); 102// m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
103 } 103 }
diff --git a/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs
index 49f2176..8d66f1b 100644
--- a/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
index 416ad16..ec76508 100644
--- a/OpenSim/Services/HypergridService/UserAgentService.cs
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -131,12 +131,18 @@ namespace OpenSim.Services.HypergridService
131 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions); 131 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions);
132 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions); 132 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions);
133 133
134 m_GridName = serverConfig.GetString("ExternalName", string.Empty); 134 m_GridName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
135 if (m_GridName == string.Empty) 135 new string[] { "Startup", "Hypergrid", "UserAgentService" }, String.Empty);
136 if (string.IsNullOrEmpty(m_GridName)) // Legacy. Remove soon.
136 { 137 {
137 serverConfig = config.Configs["GatekeeperService"];
138 m_GridName = serverConfig.GetString("ExternalName", string.Empty); 138 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
139 if (m_GridName == string.Empty)
140 {
141 serverConfig = config.Configs["GatekeeperService"];
142 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
143 }
139 } 144 }
145
140 if (!m_GridName.EndsWith("/")) 146 if (!m_GridName.EndsWith("/"))
141 m_GridName = m_GridName + "/"; 147 m_GridName = m_GridName + "/";
142 148
diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs
index c0130f1..3663a7a 100644
--- a/OpenSim/Services/Interfaces/IAvatarService.cs
+++ b/OpenSim/Services/Interfaces/IAvatarService.cs
@@ -180,11 +180,18 @@ namespace OpenSim.Services.Interfaces
180 180
181 // Attachments 181 // Attachments
182 List<AvatarAttachment> attachments = appearance.GetAttachments(); 182 List<AvatarAttachment> attachments = appearance.GetAttachments();
183 Dictionary<int, List<string>> atts = new Dictionary<int, List<string>>();
183 foreach (AvatarAttachment attach in attachments) 184 foreach (AvatarAttachment attach in attachments)
184 { 185 {
185 if (attach.ItemID != UUID.Zero) 186 if (attach.ItemID != UUID.Zero)
186 Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); 187 {
188 if (!atts.ContainsKey(attach.AttachPoint))
189 atts[attach.AttachPoint] = new List<string>();
190 atts[attach.AttachPoint].Add(attach.ItemID.ToString());
191 }
187 } 192 }
193 foreach (KeyValuePair<int, List<string>> kvp in atts)
194 Data["_ap_" + kvp.Key] = string.Join(",", kvp.Value.ToArray());
188 } 195 }
189 196
190 public AvatarAppearance ToAvatarAppearance() 197 public AvatarAppearance ToAvatarAppearance()
@@ -320,10 +327,16 @@ namespace OpenSim.Services.Interfaces
320 if (!Int32.TryParse(pointStr, out point)) 327 if (!Int32.TryParse(pointStr, out point))
321 continue; 328 continue;
322 329
323 UUID uuid = UUID.Zero; 330 List<string> idList = new List<string>(_kvp.Value.Split(new char[] {','}));
324 UUID.TryParse(_kvp.Value, out uuid);
325 331
326 appearance.SetAttachment(point, uuid, UUID.Zero); 332 appearance.SetAttachment(point, UUID.Zero, UUID.Zero);
333 foreach (string id in idList)
334 {
335 UUID uuid = UUID.Zero;
336 UUID.TryParse(id, out uuid);
337
338 appearance.SetAttachment(point | 0x80, uuid, UUID.Zero);
339 }
327 } 340 }
328 341
329 if (appearance.Wearables[AvatarWearable.BODY].Count == 0) 342 if (appearance.Wearables[AvatarWearable.BODY].Count == 0)
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/Interfaces/Properties/AssemblyInfo.cs b/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs
index 4723553..47ece75 100644
--- a/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/InventoryService/LibraryService.cs b/OpenSim/Services/InventoryService/LibraryService.cs
index f90895b..c4a5572 100644
--- a/OpenSim/Services/InventoryService/LibraryService.cs
+++ b/OpenSim/Services/InventoryService/LibraryService.cs
@@ -38,6 +38,7 @@ using OpenSim.Services.Interfaces;
38using log4net; 38using log4net;
39using Nini.Config; 39using Nini.Config;
40using OpenMetaverse; 40using OpenMetaverse;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Services.InventoryService 43namespace OpenSim.Services.InventoryService
43{ 44{
diff --git a/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs b/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs
index 41ad9f8..bfae81f 100644
--- a/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index cbb6e6c..ede2353 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -110,7 +110,8 @@ namespace OpenSim.Services.LLLoginService
110 m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true); 110 m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true);
111 m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false); 111 m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false);
112 m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); 112 m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0);
113 m_GatekeeperURL = m_LoginServerConfig.GetString("GatekeeperURI", string.Empty); 113 m_GatekeeperURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
114 new string[] { "Startup", "Hypergrid", "LoginService" }, String.Empty);
114 m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty); 115 m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty);
115 m_ProfileURL = m_LoginServerConfig.GetString("ProfileServerURL", string.Empty); 116 m_ProfileURL = m_LoginServerConfig.GetString("ProfileServerURL", string.Empty);
116 m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); 117 m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty);
@@ -969,14 +970,25 @@ namespace OpenSim.Services.LLLoginService
969 // or fixing critical issues 970 // or fixing critical issues
970 // 971 //
971 if (cmd.Length > 2) 972 if (cmd.Length > 2)
972 Int32.TryParse(cmd[2], out m_MinLoginLevel); 973 {
974 if (Int32.TryParse(cmd[2], out m_MinLoginLevel))
975 MainConsole.Instance.OutputFormat("Set minimum login level to {0}", m_MinLoginLevel);
976 else
977 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid login level", cmd[2]);
978 }
973 break; 979 break;
974 case "reset": 980
981 case "reset":
975 m_MinLoginLevel = 0; 982 m_MinLoginLevel = 0;
983 MainConsole.Instance.OutputFormat("Reset min login level to {0}", m_MinLoginLevel);
976 break; 984 break;
985
977 case "text": 986 case "text":
978 if (cmd.Length > 2) 987 if (cmd.Length > 2)
988 {
979 m_WelcomeMessage = cmd[2]; 989 m_WelcomeMessage = cmd[2];
990 MainConsole.Instance.OutputFormat("Login welcome message set to '{0}'", m_WelcomeMessage);
991 }
980 break; 992 break;
981 } 993 }
982 } 994 }
diff --git a/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs b/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs
index 62c6e0f..0a6daee 100644
--- a/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
index 23eb664..19936e5 100644
--- a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs b/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs
index 8c03dd7..5d433df 100644
--- a/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs b/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs
index 24e1d16..e7d2d6f 100644
--- a/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs
+++ b/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs
index 95c2935..772ab97 100644
--- a/OpenSim/Services/UserAccountService/UserAccountService.cs
+++ b/OpenSim/Services/UserAccountService/UserAccountService.cs
@@ -36,6 +36,7 @@ using OpenSim.Framework;
36using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
37using OpenSim.Framework.Console; 37using OpenSim.Framework.Console;
38using GridRegion = OpenSim.Services.Interfaces.GridRegion; 38using GridRegion = OpenSim.Services.Interfaces.GridRegion;
39using PermissionMask = OpenSim.Framework.PermissionMask;
39 40
40namespace OpenSim.Services.UserAccountService 41namespace OpenSim.Services.UserAccountService
41{ 42{
@@ -564,7 +565,7 @@ namespace OpenSim.Services.UserAccountService
564 return account; 565 return account;
565 } 566 }
566 567
567 private void CreateDefaultAppearanceEntries(UUID principalID) 568 protected void CreateDefaultAppearanceEntries(UUID principalID)
568 { 569 {
569 m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); 570 m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID);
570 571
@@ -684,4 +685,4 @@ namespace OpenSim.Services.UserAccountService
684 } 685 }
685 } 686 }
686 } 687 }
687} \ No newline at end of file 688}
diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
new file mode 100644
index 0000000..6cc7ff2
--- /dev/null
+++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
@@ -0,0 +1,91 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using log4net;
35using Nini.Config;
36using NUnit.Framework;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Communications;
40using OpenSim.Framework.Servers;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.CoreModules.Framework;
44using OpenSim.Tests.Common;
45using OpenSim.Tests.Common.Mock;
46
47namespace OpenSim.Tests.Common
48{
49 public static class EntityTransferHelpers
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 /// <summary>
54 /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the
55 /// viewer to setup a connection with the destination region.
56 /// </summary>
57 /// <param name='tc'></param>
58 /// <param name='neighbourTcs'>
59 /// A list that will be populated with any TestClients set up in response to
60 /// being informed about a destination region.
61 /// </param>
62 public static void SetUpInformClientOfNeighbour(TestClient tc, List<TestClient> neighbourTcs)
63 {
64 // XXX: Confusingly, this is also used for non-neighbour notification (as in teleports that do not use the
65 // event queue).
66
67 tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) =>
68 {
69 uint x, y;
70 Utils.LongToUInts(neighbourHandle, out x, out y);
71 x /= Constants.RegionSize;
72 y /= Constants.RegionSize;
73
74 m_log.DebugFormat(
75 "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}",
76 x, y, neighbourExternalEndPoint);
77
78 // In response to this message, we are going to make a teleport to the scene we've previous been told
79 // about by test code (this needs to be improved).
80 AgentCircuitData newAgent = tc.RequestClientInfo();
81
82 Scene neighbourScene;
83 SceneManager.Instance.TryGetScene(x, y, out neighbourScene);
84
85 TestClient neighbourTc = new TestClient(newAgent, neighbourScene, SceneManager.Instance);
86 neighbourTcs.Add(neighbourTc);
87 neighbourScene.AddNewClient(neighbourTc, PresenceType.User);
88 };
89 }
90 }
91} \ No newline at end of file
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index ea3e348..bdd9093 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -139,7 +139,7 @@ namespace OpenSim.Tests.Common
139 SceneCommunicationService scs = new SceneCommunicationService(); 139 SceneCommunicationService scs = new SceneCommunicationService();
140 140
141 TestScene testScene = new TestScene( 141 TestScene testScene = new TestScene(
142 regInfo, m_acm, scs, m_simDataService, m_estateDataService, false, configSource, null); 142 regInfo, m_acm, scs, m_simDataService, m_estateDataService, configSource, null);
143 143
144 INonSharedRegionModule godsModule = new GodsModule(); 144 INonSharedRegionModule godsModule = new GodsModule();
145 godsModule.Initialise(new IniConfigSource()); 145 godsModule.Initialise(new IniConfigSource());
@@ -532,6 +532,31 @@ namespace OpenSim.Tests.Common
532 /// <returns></returns> 532 /// <returns></returns>
533 public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) 533 public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager)
534 { 534 {
535 return AddScenePresence(scene, new TestClient(agentData, scene, sceneManager), agentData, sceneManager);
536 }
537
538 /// <summary>
539 /// Add a root agent.
540 /// </summary>
541 /// <remarks>
542 /// This function
543 ///
544 /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the
545 /// userserver if grid) would give initial login data back to the client and separately tell the scene that the
546 /// agent was coming.
547 ///
548 /// 2) Connects the agent with the scene
549 ///
550 /// This function performs actions equivalent with notifying the scene that an agent is
551 /// coming and then actually connecting the agent to the scene. The one step missed out is the very first
552 /// </remarks>
553 /// <param name="scene"></param>
554 /// <param name="agentData"></param>
555 /// <param name="sceneManager"></param>
556 /// <returns></returns>
557 public static ScenePresence AddScenePresence(
558 Scene scene, IClientAPI client, AgentCircuitData agentData, SceneManager sceneManager)
559 {
535 // We emulate the proper login sequence here by doing things in four stages 560 // We emulate the proper login sequence here by doing things in four stages
536 561
537 // Stage 0: login 562 // Stage 0: login
@@ -541,7 +566,7 @@ namespace OpenSim.Tests.Common
541 lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); 566 lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID);
542 567
543 // Stages 1 & 2 568 // Stages 1 & 2
544 ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); 569 ScenePresence sp = IntroduceClientToScene(scene, client, agentData, TeleportFlags.ViaLogin);
545 570
546 // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. 571 // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent.
547 sp.CompleteMovement(sp.ControllingClient, true); 572 sp.CompleteMovement(sp.ControllingClient, true);
@@ -558,11 +583,11 @@ namespace OpenSim.Tests.Common
558 /// neighbours and where no teleporting takes place. 583 /// neighbours and where no teleporting takes place.
559 /// </param> 584 /// </param>
560 /// <param name='scene'></param> 585 /// <param name='scene'></param>
561 /// <param name='sceneManager></param> 586 /// <param name='testClient'></param>
562 /// <param name='agentData'></param> 587 /// <param name='agentData'></param>
563 /// <param name='tf'></param> 588 /// <param name='tf'></param>
564 private static ScenePresence IntroduceClientToScene( 589 private static ScenePresence IntroduceClientToScene(
565 Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) 590 Scene scene, IClientAPI client, AgentCircuitData agentData, TeleportFlags tf)
566 { 591 {
567 string reason; 592 string reason;
568 593
@@ -571,10 +596,9 @@ namespace OpenSim.Tests.Common
571 Console.WriteLine("NewUserConnection failed: " + reason); 596 Console.WriteLine("NewUserConnection failed: " + reason);
572 597
573 // Stage 2: add the new client as a child agent to the scene 598 // Stage 2: add the new client as a child agent to the scene
574 TestClient client = new TestClient(agentData, scene, sceneManager);
575 scene.AddNewClient(client, PresenceType.User); 599 scene.AddNewClient(client, PresenceType.User);
576 600
577 return scene.GetScenePresence(agentData.AgentID); 601 return scene.GetScenePresence(client.AgentId);
578 } 602 }
579 603
580 public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId) 604 public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId)
@@ -583,7 +607,8 @@ namespace OpenSim.Tests.Common
583 acd.child = true; 607 acd.child = true;
584 608
585 // XXX: ViaLogin may not be correct for child agents 609 // XXX: ViaLogin may not be correct for child agents
586 return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); 610 TestClient client = new TestClient(acd, scene, null);
611 return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin);
587 } 612 }
588 613
589 /// <summary> 614 /// <summary>
diff --git a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
index 0a2b30a..bb4b55f 100644
--- a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
@@ -46,13 +46,32 @@ namespace OpenSim.Tests.Common
46 /// <param name="scene"></param> 46 /// <param name="scene"></param>
47 /// <param name="part"></param> 47 /// <param name="part"></param>
48 /// <param name="itemName"></param> 48 /// <param name="itemName"></param>
49 /// <param name="itemIDFrag">UUID or UUID stem</param>
50 /// <param name="assetIDFrag">UUID or UUID stem</param>
51 /// <param name="text">The tex to put in the notecard.</param>
52 /// <returns>The item that was added</returns>
53 public static TaskInventoryItem AddNotecard(
54 Scene scene, SceneObjectPart part, string itemName, string itemIDStem, string assetIDStem, string text)
55 {
56 return AddNotecard(
57 scene, part, itemName, TestHelpers.ParseStem(itemIDStem), TestHelpers.ParseStem(assetIDStem), text);
58 }
59
60 /// <summary>
61 /// Add a notecard item to the given part.
62 /// </summary>
63 /// <param name="scene"></param>
64 /// <param name="part"></param>
65 /// <param name="itemName"></param>
49 /// <param name="itemID"></param> 66 /// <param name="itemID"></param>
50 /// <param name="assetID"></param> 67 /// <param name="assetID"></param>
68 /// <param name="text">The tex to put in the notecard.</param>
51 /// <returns>The item that was added</returns> 69 /// <returns>The item that was added</returns>
52 public static TaskInventoryItem AddNotecard(Scene scene, SceneObjectPart part, string itemName, UUID itemID, UUID assetID) 70 public static TaskInventoryItem AddNotecard(
71 Scene scene, SceneObjectPart part, string itemName, UUID itemID, UUID assetID, string text)
53 { 72 {
54 AssetNotecard nc = new AssetNotecard(); 73 AssetNotecard nc = new AssetNotecard();
55 nc.BodyText = "Hello World!"; 74 nc.BodyText = text;
56 nc.Encode(); 75 nc.Encode();
57 76
58 AssetBase ncAsset 77 AssetBase ncAsset
@@ -87,8 +106,8 @@ namespace OpenSim.Tests.Common
87 /// Add a simple script to the given part. 106 /// Add a simple script to the given part.
88 /// </summary> 107 /// </summary>
89 /// <remarks> 108 /// <remarks>
90 /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these 109 /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather
91 /// functions more than once in a test. 110 /// than a random component.
92 /// </remarks> 111 /// </remarks>
93 /// <param name="scene"></param> 112 /// <param name="scene"></param>
94 /// <param name="part"></param> 113 /// <param name="part"></param>
@@ -102,8 +121,9 @@ namespace OpenSim.Tests.Common
102 ast.Source = scriptSource; 121 ast.Source = scriptSource;
103 ast.Encode(); 122 ast.Encode();
104 123
105 UUID assetUuid = new UUID("00000000-0000-0000-1000-000000000000"); 124 UUID assetUuid = UUID.Random();
106 UUID itemUuid = new UUID("00000000-0000-0000-1100-000000000000"); 125 UUID itemUuid = UUID.Random();
126
107 AssetBase asset 127 AssetBase asset
108 = AssetHelpers.CreateAsset(assetUuid, AssetType.LSLText, ast.AssetData, UUID.Zero); 128 = AssetHelpers.CreateAsset(assetUuid, AssetType.LSLText, ast.AssetData, UUID.Zero);
109 scene.AssetService.Store(asset); 129 scene.AssetService.Store(asset);
diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
index 87d9410..a1794c9 100644
--- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
@@ -45,6 +45,9 @@ namespace OpenSim.Tests.Common
45 /// <summary> 45 /// <summary>
46 /// Add an existing scene object as an item in the user's inventory. 46 /// Add an existing scene object as an item in the user's inventory.
47 /// </summary> 47 /// </summary>
48 /// <remarks>
49 /// Will be added to the system Objects folder.
50 /// </remarks>
48 /// <param name='scene'></param> 51 /// <param name='scene'></param>
49 /// <param name='so'></param> 52 /// <param name='so'></param>
50 /// <param name='inventoryIdTail'></param> 53 /// <param name='inventoryIdTail'></param>
@@ -63,7 +66,29 @@ namespace OpenSim.Tests.Common
63 } 66 }
64 67
65 /// <summary> 68 /// <summary>
66 /// Creates a notecard in the objects folder and specify an item id. 69 /// Add an existing scene object as an item in the user's inventory at the given path.
70 /// </summary>
71 /// <param name='scene'></param>
72 /// <param name='so'></param>
73 /// <param name='inventoryIdTail'></param>
74 /// <param name='assetIdTail'></param>
75 /// <returns>The inventory item created.</returns>
76 public static InventoryItemBase AddInventoryItem(
77 Scene scene, SceneObjectGroup so, int inventoryIdTail, int assetIdTail, string path)
78 {
79 return AddInventoryItem(
80 scene,
81 so.Name,
82 TestHelpers.ParseTail(inventoryIdTail),
83 InventoryType.Object,
84 AssetHelpers.CreateAsset(TestHelpers.ParseTail(assetIdTail), so),
85 so.OwnerID,
86 path);
87 }
88
89 /// <summary>
90 /// Adds the given item to the existing system folder for its type (e.g. an object will go in the "Objects"
91 /// folder).
67 /// </summary> 92 /// </summary>
68 /// <param name="scene"></param> 93 /// <param name="scene"></param>
69 /// <param name="itemName"></param> 94 /// <param name="itemName"></param>
@@ -75,6 +100,25 @@ namespace OpenSim.Tests.Common
75 private static InventoryItemBase AddInventoryItem( 100 private static InventoryItemBase AddInventoryItem(
76 Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId) 101 Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId)
77 { 102 {
103 return AddInventoryItem(
104 scene, itemName, itemId, itemType, asset, userId,
105 scene.InventoryService.GetFolderForType(userId, (AssetType)asset.Type).Name);
106 }
107
108 /// <summary>
109 /// Adds the given item to an inventory folder
110 /// </summary>
111 /// <param name="scene"></param>
112 /// <param name="itemName"></param>
113 /// <param name="itemId"></param>
114 /// <param name="itemType"></param>
115 /// <param name="asset">The serialized asset for this item</param>
116 /// <param name="userId"></param>
117 /// <param name="path">Existing inventory path at which to add.</param>
118 /// <returns></returns>
119 private static InventoryItemBase AddInventoryItem(
120 Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId, string path)
121 {
78 scene.AssetService.Store(asset); 122 scene.AssetService.Store(asset);
79 123
80 InventoryItemBase item = new InventoryItemBase(); 124 InventoryItemBase item = new InventoryItemBase();
@@ -85,7 +129,7 @@ namespace OpenSim.Tests.Common
85 item.AssetType = asset.Type; 129 item.AssetType = asset.Type;
86 item.InvType = (int)itemType; 130 item.InvType = (int)itemType;
87 131
88 InventoryFolderBase folder = scene.InventoryService.GetFolderForType(userId, (AssetType)asset.Type); 132 InventoryFolderBase folder = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, path)[0];
89 133
90 item.Folder = folder.ID; 134 item.Folder = folder.ID;
91 scene.AddInventoryItem(item); 135 scene.AddInventoryItem(item);
@@ -156,58 +200,83 @@ namespace OpenSim.Tests.Common
156 /// <summary> 200 /// <summary>
157 /// Create inventory folders starting from the user's root folder. 201 /// Create inventory folders starting from the user's root folder.
158 /// </summary> 202 /// </summary>
159 ///
160 /// Ignores any existing folders with the same name
161 ///
162 /// <param name="inventoryService"></param> 203 /// <param name="inventoryService"></param>
163 /// <param name="userId"></param> 204 /// <param name="userId"></param>
164 /// <param name="path"> 205 /// <param name="path">
165 /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER 206 /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER
166 /// </param> 207 /// </param>
208 /// <param name="useExistingFolders">
209 /// If true, then folders in the path which already the same name are
210 /// used. This applies to the terminal folder as well.
211 /// If false, then all folders in the path are created, even if there is already a folder at a particular
212 /// level with the same name.
213 /// </param>
167 /// <returns> 214 /// <returns>
168 /// The folder created. If the path contains multiple folders then the last one created is returned. 215 /// The folder created. If the path contains multiple folders then the last one created is returned.
169 /// Will return null if the root folder could not be found. 216 /// Will return null if the root folder could not be found.
170 /// </returns> 217 /// </returns>
171 public static InventoryFolderBase CreateInventoryFolder( 218 public static InventoryFolderBase CreateInventoryFolder(
172 IInventoryService inventoryService, UUID userId, string path) 219 IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders)
173 { 220 {
174 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 221 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
175 222
176 if (null == rootFolder) 223 if (null == rootFolder)
177 return null; 224 return null;
178 225
179 return CreateInventoryFolder(inventoryService, rootFolder, path); 226 return CreateInventoryFolder(inventoryService, rootFolder, path, useExistingFolders);
180 } 227 }
181 228
182 /// <summary> 229 /// <summary>
183 /// Create inventory folders starting from a given parent folder 230 /// Create inventory folders starting from a given parent folder
184 /// </summary> 231 /// </summary>
185 /// 232 /// <remarks>
186 /// Ignores any existing folders with the same name 233 /// If any stem of the path names folders that already exist then these are not recreated. This includes the
187 /// 234 /// final folder.
235 /// TODO: May need to make it an option to create duplicate folders.
236 /// </remarks>
188 /// <param name="inventoryService"></param> 237 /// <param name="inventoryService"></param>
189 /// <param name="parentFolder"></param> 238 /// <param name="parentFolder"></param>
190 /// <param name="path"> 239 /// <param name="path">
191 /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER 240 /// The folder to create.
241 /// </param>
242 /// <param name="useExistingFolders">
243 /// If true, then folders in the path which already the same name are
244 /// used. This applies to the terminal folder as well.
245 /// If false, then all folders in the path are created, even if there is already a folder at a particular
246 /// level with the same name.
192 /// </param> 247 /// </param>
193 /// <returns> 248 /// <returns>
194 /// The folder created. If the path contains multiple folders then the last one created is returned. 249 /// The folder created. If the path contains multiple folders then the last one created is returned.
195 /// </returns> 250 /// </returns>
196 public static InventoryFolderBase CreateInventoryFolder( 251 public static InventoryFolderBase CreateInventoryFolder(
197 IInventoryService inventoryService, InventoryFolderBase parentFolder, string path) 252 IInventoryService inventoryService, InventoryFolderBase parentFolder, string path, bool useExistingFolders)
198 { 253 {
199 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); 254 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);
200 255
201 InventoryFolderBase newFolder 256 InventoryFolderBase folder = null;
202 = new InventoryFolderBase( 257
203 UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); 258 if (useExistingFolders)
204 259 folder = InventoryArchiveUtils.FindFolderByPath(inventoryService, parentFolder, components[0]);
205 inventoryService.AddFolder(newFolder); 260
261 if (folder == null)
262 {
263// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name);
264
265 folder
266 = new InventoryFolderBase(
267 UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0);
268
269 inventoryService.AddFolder(folder);
270 }
271// else
272// {
273// Console.WriteLine("Found existing folder {0}", folder.Name);
274// }
206 275
207 if (components.Length > 1) 276 if (components.Length > 1)
208 return CreateInventoryFolder(inventoryService, newFolder, components[1]); 277 return CreateInventoryFolder(inventoryService, folder, components[1], useExistingFolders);
209 else 278 else
210 return newFolder; 279 return folder;
211 } 280 }
212 281
213 /// <summary> 282 /// <summary>
@@ -237,7 +306,7 @@ namespace OpenSim.Tests.Common
237 /// <returns>An empty list if no matching folders were found</returns> 306 /// <returns>An empty list if no matching folders were found</returns>
238 public static List<InventoryFolderBase> GetInventoryFolders(IInventoryService inventoryService, UUID userId, string path) 307 public static List<InventoryFolderBase> GetInventoryFolders(IInventoryService inventoryService, UUID userId, string path)
239 { 308 {
240 return InventoryArchiveUtils.FindFolderByPath(inventoryService, userId, path); 309 return InventoryArchiveUtils.FindFoldersByPath(inventoryService, userId, path);
241 } 310 }
242 311
243 /// <summary> 312 /// <summary>
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/MockScriptEngine.cs b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs
new file mode 100644
index 0000000..b444241
--- /dev/null
+++ b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs
@@ -0,0 +1,266 @@
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.Reflection;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.Interfaces;
38using OpenSim.Region.ScriptEngine.Shared;
39
40namespace OpenSim.Tests.Common
41{
42 public class MockScriptEngine : INonSharedRegionModule, IScriptModule, IScriptEngine
43 {
44 public IConfigSource ConfigSource { get; private set; }
45
46 public IConfig Config { get; private set; }
47
48 private Scene m_scene;
49
50 /// <summary>
51 /// Expose posted events to tests.
52 /// </summary>
53 public Dictionary<UUID, List<EventParams>> PostedEvents { get; private set; }
54
55 /// <summary>
56 /// A very primitive way of hooking text cose to a posed event.
57 /// </summary>
58 /// <remarks>
59 /// May be replaced with something that uses more original code in the future.
60 /// </remarks>
61 public event Action<UUID, EventParams> PostEventHook;
62
63 public void Initialise(IConfigSource source)
64 {
65 ConfigSource = source;
66
67 // Can set later on if required
68 Config = new IniConfig("MockScriptEngine", ConfigSource);
69
70 PostedEvents = new Dictionary<UUID, List<EventParams>>();
71 }
72
73 public void Close()
74 {
75 }
76
77 public void AddRegion(Scene scene)
78 {
79 m_scene = scene;
80
81 m_scene.StackModuleInterface<IScriptModule>(this);
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86 }
87
88 public void RegionLoaded(Scene scene)
89 {
90 }
91
92 public string Name { get { return "Mock Script Engine"; } }
93 public string ScriptEngineName { get { return Name; } }
94
95 public Type ReplaceableInterface { get { return null; } }
96
97 public event ScriptRemoved OnScriptRemoved;
98 public event ObjectRemoved OnObjectRemoved;
99
100 public string GetXMLState (UUID itemID)
101 {
102 throw new System.NotImplementedException ();
103 }
104
105 public bool SetXMLState(UUID itemID, string xml)
106 {
107 throw new System.NotImplementedException ();
108 }
109
110 public bool PostScriptEvent(UUID itemID, string name, object[] args)
111 {
112// Console.WriteLine("Posting event {0} for {1}", name, itemID);
113
114 return PostScriptEvent(itemID, new EventParams(name, args, null));
115 }
116
117 public bool PostScriptEvent(UUID itemID, EventParams evParams)
118 {
119 List<EventParams> eventsForItem;
120
121 if (!PostedEvents.ContainsKey(itemID))
122 {
123 eventsForItem = new List<EventParams>();
124 PostedEvents.Add(itemID, eventsForItem);
125 }
126 else
127 {
128 eventsForItem = PostedEvents[itemID];
129 }
130
131 eventsForItem.Add(evParams);
132
133 if (PostEventHook != null)
134 PostEventHook(itemID, evParams);
135
136 return true;
137 }
138
139 public bool PostObjectEvent(uint localID, EventParams evParams)
140 {
141 return PostObjectEvent(m_scene.GetSceneObjectPart(localID), evParams);
142 }
143
144 public bool PostObjectEvent(UUID itemID, string name, object[] args)
145 {
146 return PostObjectEvent(m_scene.GetSceneObjectPart(itemID), new EventParams(name, args, null));
147 }
148
149 private bool PostObjectEvent(SceneObjectPart part, EventParams evParams)
150 {
151 foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems(InventoryType.LSL))
152 PostScriptEvent(item.ItemID, evParams);
153
154 return true;
155 }
156
157 public void SuspendScript(UUID itemID)
158 {
159 throw new System.NotImplementedException ();
160 }
161
162 public void ResumeScript(UUID itemID)
163 {
164 throw new System.NotImplementedException ();
165 }
166
167 public ArrayList GetScriptErrors(UUID itemID)
168 {
169 throw new System.NotImplementedException ();
170 }
171
172 public bool HasScript(UUID itemID, out bool running)
173 {
174 throw new System.NotImplementedException ();
175 }
176
177 public bool GetScriptState(UUID itemID)
178 {
179 throw new System.NotImplementedException ();
180 }
181
182 public void SaveAllState()
183 {
184 throw new System.NotImplementedException ();
185 }
186
187 public void StartProcessing()
188 {
189 throw new System.NotImplementedException ();
190 }
191
192 public float GetScriptExecutionTime(List<UUID> itemIDs)
193 {
194 throw new System.NotImplementedException ();
195 }
196
197 public Dictionary<uint, float> GetObjectScriptsExecutionTimes()
198 {
199 throw new System.NotImplementedException ();
200 }
201
202 public IScriptWorkItem QueueEventHandler(object parms)
203 {
204 throw new System.NotImplementedException ();
205 }
206
207 public DetectParams GetDetectParams(UUID item, int number)
208 {
209 throw new System.NotImplementedException ();
210 }
211
212 public void SetMinEventDelay(UUID itemID, double delay)
213 {
214 throw new System.NotImplementedException ();
215 }
216
217 public int GetStartParameter(UUID itemID)
218 {
219 throw new System.NotImplementedException ();
220 }
221
222 public void SetScriptState(UUID itemID, bool state)
223 {
224 throw new System.NotImplementedException ();
225 }
226
227 public void SetState(UUID itemID, string newState)
228 {
229 throw new System.NotImplementedException ();
230 }
231
232 public void ApiResetScript(UUID itemID)
233 {
234 throw new System.NotImplementedException ();
235 }
236
237 public void ResetScript (UUID itemID)
238 {
239 throw new System.NotImplementedException ();
240 }
241
242 public IScriptApi GetApi(UUID itemID, string name)
243 {
244 throw new System.NotImplementedException ();
245 }
246
247 public Scene World { get { return m_scene; } }
248
249 public IScriptModule ScriptModule { get { return this; } }
250
251 public string ScriptEnginePath { get { throw new System.NotImplementedException (); }}
252
253 public string ScriptClassName { get { throw new System.NotImplementedException (); } }
254
255 public string ScriptBaseClassName { get { throw new System.NotImplementedException (); } }
256
257 public string[] ScriptReferencedAssemblies { get { throw new System.NotImplementedException (); } }
258
259 public ParameterInfo[] ScriptBaseClassParameters { get { throw new System.NotImplementedException (); } }
260
261 public void ClearPostedEvents()
262 {
263 PostedEvents.Clear();
264 }
265 }
266} \ No newline at end of file
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 2714429..07de06c 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -46,8 +46,6 @@ namespace OpenSim.Tests.Common.Mock
46 46
47 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); 47 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
48 48
49 private TestClient TeleportSceneClient;
50
51 private Scene m_scene; 49 private Scene m_scene;
52 private SceneManager m_sceneManager; 50 private SceneManager m_sceneManager;
53 51
@@ -60,6 +58,10 @@ namespace OpenSim.Tests.Common.Mock
60 public List<ImagePacketPacket> SentImagePacketPackets { get; private set; } 58 public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
61 public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; } 59 public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; }
62 60
61 // Test client specific events - for use by tests to implement some IClientAPI behaviour.
62 public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
63 public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour;
64
63// disable warning: public events, part of the public API 65// disable warning: public events, part of the public API
64#pragma warning disable 67 66#pragma warning disable 67
65 67
@@ -548,12 +550,12 @@ namespace OpenSim.Tests.Common.Mock
548 550
549 } 551 }
550 552
551 public void SendGenericMessage(string method, List<string> message) 553 public void SendGenericMessage(string method, UUID invoice, List<string> message)
552 { 554 {
553 555
554 } 556 }
555 557
556 public void SendGenericMessage(string method, List<byte[]> message) 558 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
557 { 559 {
558 560
559 } 561 }
@@ -575,6 +577,8 @@ namespace OpenSim.Tests.Common.Mock
575 577
576 public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 578 public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
577 { 579 {
580 if (OnReceivedMoveAgentIntoRegion != null)
581 OnReceivedMoveAgentIntoRegion(regInfo, pos, look);
578 } 582 }
579 583
580 public virtual AgentCircuitData RequestClientInfo() 584 public virtual AgentCircuitData RequestClientInfo()
@@ -600,23 +604,8 @@ namespace OpenSim.Tests.Common.Mock
600 604
601 public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) 605 public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint)
602 { 606 {
603 m_log.DebugFormat("[TEST CLIENT]: Processing inform client of neighbour"); 607 if (OnTestClientInformClientOfNeighbour != null)
604 608 OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint);
605 // In response to this message, we are going to make a teleport to the scene we've previous been told
606 // about by test code (this needs to be improved).
607 AgentCircuitData newAgent = RequestClientInfo();
608
609 // Stage 2: add the new client as a child agent to the scene
610 uint x, y;
611 Utils.LongToUInts(neighbourHandle, out x, out y);
612 x /= Constants.RegionSize;
613 y /= Constants.RegionSize;
614
615 Scene neighbourScene;
616 m_sceneManager.TryGetScene(x, y, out neighbourScene);
617
618 TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager);
619 neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User);
620 } 609 }
621 610
622 public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 611 public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
@@ -631,12 +620,6 @@ namespace OpenSim.Tests.Common.Mock
631 // CompleteTeleportClientSide(); 620 // CompleteTeleportClientSide();
632 } 621 }
633 622
634 public void CompleteTeleportClientSide()
635 {
636 TeleportSceneClient.CompleteMovement();
637 //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false);
638 }
639
640 public virtual void SendTeleportFailed(string reason) 623 public virtual void SendTeleportFailed(string reason)
641 { 624 {
642 m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason); 625 m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason);
diff --git a/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs
new file mode 100644
index 0000000..6707019
--- /dev/null
+++ b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs
@@ -0,0 +1,178 @@
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.Net;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using Nini.Config;
36using Mono.Addins;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43
44namespace OpenSim.Tests.Common
45{
46 public class TestEventQueueGetModule : IEventQueue, INonSharedRegionModule
47 {
48 public class Event
49 {
50 public string Name { get; set; }
51 public object[] Args { get; set; }
52
53 public Event(string name, object[] args)
54 {
55 name = Name;
56 args = Args;
57 }
58 }
59
60 public Dictionary<UUID, List<Event>> Events { get; set; }
61
62 public void Initialise(IConfigSource source) {}
63
64 public void Close() {}
65
66 public void AddRegion(Scene scene)
67 {
68 Events = new Dictionary<UUID, List<Event>>();
69 scene.RegisterModuleInterface<IEventQueue>(this);
70 }
71
72 public void RemoveRegion (Scene scene) {}
73
74 public void RegionLoaded (Scene scene) {}
75
76 public string Name { get { return "TestEventQueueGetModule"; } }
77
78 public Type ReplaceableInterface { get { return null; } }
79
80 private void AddEvent(UUID avatarID, string name, params object[] args)
81 {
82 Console.WriteLine("Adding event {0} for {1}", name, avatarID);
83
84 List<Event> avEvents;
85
86 if (!Events.ContainsKey(avatarID))
87 {
88 avEvents = new List<Event>();
89 Events[avatarID] = avEvents;
90 }
91 else
92 {
93 avEvents = Events[avatarID];
94 }
95
96 avEvents.Add(new Event(name, args));
97 }
98
99 public void ClearEvents()
100 {
101 if (Events != null)
102 Events.Clear();
103 }
104
105 public bool Enqueue(OSD o, UUID avatarID)
106 {
107 AddEvent(avatarID, "Enqueue", o);
108 return true;
109 }
110
111 public void DisableSimulator(ulong handle, UUID avatarID)
112 {
113 AddEvent(avatarID, "DisableSimulator", handle);
114 }
115
116 public void EnableSimulator (ulong handle, IPEndPoint endPoint, UUID avatarID)
117 {
118 AddEvent(avatarID, "EnableSimulator", handle);
119 }
120
121 public void EstablishAgentCommunication (UUID avatarID, IPEndPoint endPoint, string capsPath)
122 {
123 AddEvent(avatarID, "EstablishAgentCommunication", endPoint, capsPath);
124 }
125
126 public void TeleportFinishEvent (ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, uint locationID, uint flags, string capsURL, UUID agentID)
127 {
128 AddEvent(agentID, "TeleportFinishEvent", regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL);
129 }
130
131 public void CrossRegion (ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID avatarID, UUID sessionID)
132 {
133 AddEvent(avatarID, "CrossRegion", handle, pos, lookAt, newRegionExternalEndPoint, capsURL, sessionID);
134 }
135
136 public void ChatterboxInvitation(
137 UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName,
138 byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl,
139 UUID transactionID, bool fromGroup, byte[] binaryBucket)
140 {
141 AddEvent(
142 toAgent, "ChatterboxInvitation", sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
143 timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket);
144 }
145
146 public void ChatterBoxSessionAgentListUpdates (UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, bool isModerator, bool textMute)
147 {
148 AddEvent(toAgent, "ChatterBoxSessionAgentListUpdates", sessionID, fromAgent, canVoiceChat, isModerator, textMute);
149 }
150
151 public void ParcelProperties (OpenMetaverse.Messages.Linden.ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
152 {
153 AddEvent(avatarID, "ParcelProperties", parcelPropertiesMessage);
154 }
155
156 public void GroupMembership (OpenMetaverse.Packets.AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
157 {
158 AddEvent(avatarID, "GroupMembership", groupUpdate);
159 }
160
161 public OSD ScriptRunningEvent (UUID objectID, UUID itemID, bool running, bool mono)
162 {
163 Console.WriteLine("ONE");
164 throw new System.NotImplementedException ();
165 }
166
167 public OSD BuildEvent (string eventName, OSD eventBody)
168 {
169 Console.WriteLine("TWO");
170 throw new System.NotImplementedException ();
171 }
172
173 public void partPhysicsProperties (uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID)
174 {
175 AddEvent(avatarID, "partPhysicsProperties", localID, physhapetype, density, friction, bounce, gravmod);
176 }
177 }
178} \ No newline at end of file
diff --git a/OpenSim/Tests/Common/Mock/TestLandChannel.cs b/OpenSim/Tests/Common/Mock/TestLandChannel.cs
index 4b4d52d..3115035 100644
--- a/OpenSim/Tests/Common/Mock/TestLandChannel.cs
+++ b/OpenSim/Tests/Common/Mock/TestLandChannel.cs
@@ -81,6 +81,11 @@ namespace OpenSim.Tests.Common.Mock
81 return obj; 81 return obj;
82 } 82 }
83 83
84 public ILandObject GetLandObject(Vector3 position)
85 {
86 return GetLandObject(position.X, position.Y);
87 }
88
84 public ILandObject GetLandObject(int x, int y) 89 public ILandObject GetLandObject(int x, int y)
85 { 90 {
86 return GetNoLand(); 91 return GetNoLand();
diff --git a/OpenSim/Tests/Common/Mock/TestScene.cs b/OpenSim/Tests/Common/Mock/TestScene.cs
index d4b5648..a7e0dfb 100644
--- a/OpenSim/Tests/Common/Mock/TestScene.cs
+++ b/OpenSim/Tests/Common/Mock/TestScene.cs
@@ -41,10 +41,9 @@ namespace OpenSim.Tests.Common.Mock
41 public TestScene( 41 public TestScene(
42 RegionInfo regInfo, AgentCircuitManager authen, 42 RegionInfo regInfo, AgentCircuitManager authen,
43 SceneCommunicationService sceneGridService, ISimulationDataService simDataService, IEstateDataService estateDataService, 43 SceneCommunicationService sceneGridService, ISimulationDataService simDataService, IEstateDataService estateDataService,
44 bool dumpAssetsToFile,
45 IConfigSource config, string simulatorVersion) 44 IConfigSource config, string simulatorVersion)
46 : base(regInfo, authen, sceneGridService, simDataService, estateDataService, 45 : base(regInfo, authen, sceneGridService, simDataService, estateDataService,
47 dumpAssetsToFile, config, simulatorVersion) 46 config, simulatorVersion)
48 { 47 {
49 } 48 }
50 49
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/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs
index 57da802..a684d72 100644
--- a/OpenSim/Tests/Common/TestHelpers.cs
+++ b/OpenSim/Tests/Common/TestHelpers.cs
@@ -114,6 +114,27 @@ namespace OpenSim.Tests.Common
114 } 114 }
115 115
116 /// <summary> 116 /// <summary>
117 /// Parse a UUID stem into a full UUID.
118 /// </summary>
119 /// <remarks>
120 /// Yes, this is completely inconsistent with ParseTail but this is probably a better way to do it,
121 /// UUIDs are conceptually not hexadecmial numbers.
122 /// The fragment will come at the start of the UUID. The rest will be 0s
123 /// </remarks>
124 /// <returns></returns>
125 /// <param name='frag'>
126 /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain
127 /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is
128 /// given as the 'fragment'.
129 /// </param>
130 public static UUID ParseStem(string stem)
131 {
132 string rawUuid = stem.PadRight(32, '0');
133
134 return UUID.Parse(rawUuid);
135 }
136
137 /// <summary>
117 /// Parse tail section into full UUID. 138 /// Parse tail section into full UUID.
118 /// </summary> 139 /// </summary>
119 /// <param name="tail"></param> 140 /// <param name="tail"></param>
diff --git a/OpenSim/Tests/ConfigurationLoaderTest.cs b/OpenSim/Tests/ConfigurationLoaderTest.cs
index 067264d..a409a13 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;
@@ -44,8 +45,10 @@ namespace OpenSim.Tests
44 /// Set up a test directory. 45 /// Set up a test directory.
45 /// </summary> 46 /// </summary>
46 [SetUp] 47 [SetUp]
47 public void SetUp() 48 public override void SetUp()
48 { 49 {
50 base.SetUp();
51
49 m_basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 52 m_basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
50 string path = Path.Combine(m_basePath, m_testSubdirectory); 53 string path = Path.Combine(m_basePath, m_testSubdirectory);
51 Directory.CreateDirectory(path); 54 Directory.CreateDirectory(path);
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/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs b/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs
index e1a1fda..088be45 100644
--- a/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs
+++ b/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs b/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs
index 62a2f2d..0348628 100644
--- a/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs
+++ b/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs
index daaa3c0..9821180 100644
--- a/OpenSim/Tools/pCampBot/Bot.cs
+++ b/OpenSim/Tools/pCampBot/Bot.cs
@@ -40,6 +40,7 @@ using OpenSim.Framework;
40using OpenSim.Framework.Console; 40using OpenSim.Framework.Console;
41using pCampBot.Interfaces; 41using pCampBot.Interfaces;
42using Timer = System.Timers.Timer; 42using Timer = System.Timers.Timer;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace pCampBot 45namespace pCampBot
45{ 46{
@@ -362,7 +363,7 @@ namespace pCampBot
362 asset.Encode(); 363 asset.Encode();
363 transid = Client.Assets.RequestUpload(asset,true); 364 transid = Client.Assets.RequestUpload(asset,true);
364 Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing, 365 Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing,
365 transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) 366 transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
366 { 367 {
367 if (success) 368 if (success)
368 { 369 {
@@ -386,7 +387,7 @@ namespace pCampBot
386 asset.Encode(); 387 asset.Encode();
387 transid = Client.Assets.RequestUpload(asset,true); 388 transid = Client.Assets.RequestUpload(asset,true);
388 Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart, 389 Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart,
389 transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) 390 transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
390 { 391 {
391 if (success) 392 if (success)
392 { 393 {
diff --git a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
index 20598f1..78f3603 100644
--- a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
+++ b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33